在 C 和 C++ 中初始化数组的常用方法是:
int a[3] = { 0, 1, 2 };
Aside: And you can optionally leave out the array bound and have it deduced from the initializer list, or have a larger bound than there are initializers:
int aa[] = { 0, 1, 2 }; // another array of three ints
int aaa[5] = { 0, 1, 2 }; // equivalent to { 0, 1, 2, 0, 0}
对于字符数组,有一个特殊的规则,允许从字符串文字初始化数组,数组的每个元素都从字符串文字中相应的字符初始化。
您的第一个示例使用字符串文字"D:"
因此数组的每个元素将被初始化为该字符串中的一个字符,相当于:
char disk[3] = { 'D', ':', '\0' };
(第三个字符是空终止符 https://en.wikipedia.org/wiki/Null-terminated_string,它隐式存在于所有字符串文字中)。
Aside: Here too you can optionally leave out the array bound and have it deduced from the string literal, or have a larger bound than the string length:
char dd[] = "D:"; // another array of three chars
char ddd[5] = "D:"; // equivalent to { 'D', ':', '\0', '\0', '\0'}
Just like the aaa
example above, the extra elements in ddd
that don't have a corresponding character in the string will be zero-initialized.
你的第二个例子之所以有效,是因为字符串文字"D:"
将由编译器输出并作为三个字符的数组存储在可执行文件中的某个位置。当可执行文件运行时,包含数组(和其他常量)的段将被映射到进程的地址空间。所以你的char*
然后,指针被初始化为指向该数组的位置,无论它位于何处。从概念上讲,它类似于:
const char __some_array_created_by_the_compiler[3] = "D:";
const char* disk = __some_array_created_by_the_compiler;
由于历史原因(主要是const
C) 早期不存在,使用非常量是合法的char*
指向该数组,即使该数组实际上是只读的,因此 C 和第一个 C++ 标准允许您使用非常量char*
指向字符串文字的指针,即使它引用的数组实际上是 const:
const char __some_array_created_by_the_compiler[3] = "D:";
char* disk = (char*)__some_array_created_by_the_compiler;
这意味着尽管看起来你的两个例子并不完全相同,因为这仅适用于第一个:
disk[0] = 'C';
对于第一个示例,它会更改数组的第一个元素。
对于第二个例子,它可能会编译,但结果是未定义的行为 https://en.wikipedia.org/wiki/Undefined_behavior,因为它实际上做的是修改第一个元素__some_array_created_by_the_compiler
这是只读的。实际上,可能发生的情况是进程会崩溃,因为尝试写入只读内存页会引发分段错误。
重要的是要理解,C++ 中有很多东西(C 中甚至更多)编译器会很乐意编译它们,但在执行代码时会导致非常糟糕的事情发生。