基于字符数组s[]的s,&s

看这样一段代码:

#include <iostream>
using namespace std;

int main()
{
    const char s[] = "hello";

    cout << "Array content (s): " << s << endl;       // 输出字符串内容
    cout << "Address of s (&s): " << &s << endl;     // 输出整个数组的地址
    cout << "Address of s[0] (s): " << (void*)s << endl; // 强制转换输出地址
}

输出如下:

img

输出结果解释

  • Array content (s): hello

    s 被解释为字符串的首地址,因此输出字符串内容。

  • Address of s (&s): 0x70fe10

    &s 是整个数组的地址,和数组首地址一致,但类型不同。

  • Address of s[0] (s): 0x70fe10

    s 被转换为 void*,明确输出其地址。

着重解释下为什么s 被解释为字符串的首地址,因此输出字符串内容

详细原因与机制

  1. 数组名的退化

    • 在 C 和 C++ 中,当数组名 s 在需要指针的上下文中使用时,它会退化为一个指向数组首元素的指针(即 &s[0])。这种退化适用于大多数场景,例如传参或与指针运算。

    • 但注意,此时数组名 s 并不是一个指针,它是一个常量,表示数组首元素的地址。

  2. cout 的行为

    • cout 是一个流输出对象,它对不同类型的输入进行了重载:

    • 如果输入的是指向 char 的指针(即 const char*char*),cout 会将其解释为一个 C 风格字符串,并输出字符串内容。

    • 如果输入的是其他类型的指针,例如 void*int*,cout 会输出这个指针的地址。

    在该代码中,s 退化为 const char*,因此 cout 将其解释为 C 风格字符串并输出 "hello"。

  3. 字符串的存储

const char s[] = "hello"; 实际上在内存中分配了一个 6 字节的数组:

地址       内容
0x70fe10   'h'
0x70fe11   'e'
0x70fe12   'l'
0x70fe13   'l'
0x70fe14   'o'
0x70fe15   '\0'

当 s 被用作 cout 的参数时,s 退化为 &s[0](即 0x70fe10),因此 cout 会从该地址开始,逐字节读取字符并输出,直到遇到字符串的终止符 \0。

着重解释下s和&s

  1. s 是什么?

    • s 是一个字符数组,const char s[] = "hello"; 定义了一个大小为 6(包括字符串末尾的空字符 \0)的数组。

    • s 的类型是 const char[6]。

  2. &s 是什么?

    • &s 是整个数组 s 的地址,而不是数组的第一个元素的地址(s 和 &s 在语义上不同)。

    • s 表示数组首元素(s[0])的地址,类型是 const char*

    • &s 表示整个数组的地址,类型是 const char (*)[6]

  3. cout 如何处理 &s?

    • 在 cout 中,标准输出流没有重载对 const char (*)[N] 类型的直接处理。

    • 当传递 &s 时,它会退化为一个指向数组的指针。

    • 通常,C++ 的 cout 会将指针解释为地址,并输出地址值(例如 0x70fe10)。

插句题外话

img

看这段代码,应该能更明白s和&s。

posted @ 2024-11-17 00:55  hisun9  阅读(48)  评论(0)    收藏  举报