为什么C++变量在指针时不需要正确定义?

Jam*_*ole 3 c++ arrays pointers declaration char

我对C++语言完全陌生(特别是指针,经验主要是在PHP中)并且希望对以下内容有所解释(我已经尝试过寻找答案).

两行代码如何能够在我的程序中完成相同的工作?第二行似乎违背了我迄今为止所学到的和关于指针所理解的一切.

char disk[3] = "D:";

char* disk = "D:";

我怎么能初始化指向内存地址以外的任何指针?不仅如此,在第二行我也没有正确地声明阵列 - 但它仍在工作?

Jon*_*ely 7

在C和C++中初始化数组的常用方法是:

int a[3] = { 0, 1, 2 };
Run Code Online (Sandbox Code Playgroud)
旁白:您可以选择省略数组绑定并从初始化列表中推导出它,或者具有比初始化器更大的边界:
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' };
Run Code Online (Sandbox Code Playgroud)

(第三个字符是空终止符,它隐式存在于所有字符串文字中).

旁白:在这里你也可以选择省略数组绑定并从字符串文字推导出它,或者具有比字符串长度更大的边界:
char dd[] = "D:";    // another array of three chars
char ddd[5] = "D:";  // equivalent to { 'D', ':', '\0', '\0', '\0'}
就像aaa上面的例子一样,ddd字符串中没有相应字符的额外元素将被零初始化.

您的第二个示例有效,因为字符串文字"D:"将由编译器输出并存储在可执行文件中的某个位置,作为三个字符的数组.运行可执行文件时,包含该数组的段(以及其他常量)将映射到进程的地址空间.因此,char*然后将指针初始化为指向该数组的位置,无论发生在何处.从概念上讲,它类似于:

const char __some_array_created_by_the_compiler[3] = "D:";
const char* disk = __some_array_created_by_the_compiler;
Run Code Online (Sandbox Code Playgroud)

由于历史原因(大多数const在C的早期并不存在),使用非const char*指向该数组是合法的,即使该数组实际上是只读的,因此C和第一个C++标准允许您使用非const char*指针指向字符串文字,即使它引用的数组实际上是const:

const char __some_array_created_by_the_compiler[3] = "D:";
char* disk = (char*)__some_array_created_by_the_compiler;
Run Code Online (Sandbox Code Playgroud)

这意味着尽管出现了两个例子并不完全相同,因为这只允许第一个:

disk[0] = 'C';
Run Code Online (Sandbox Code Playgroud)

对于第一个没有问题的例子,它改变了数组的第一个元素.

对于第二个示例,它可能会编译,但它会导致未定义的行为,因为它实际上正在做的是修改__some_array_created_by_the_compiler只读的第一个元素.在实践中,可能发生的是该过程将崩溃,因为尝试写入只读内存页面将引发分段错误.

重要的是要理解C++中有很多东西(甚至更多在C语言中),编译器很乐意编译它们,但是当代码执行时会导致非常糟糕的事情发生.


Nat*_*ica 5

char disk[3] = "D:";
Run Code Online (Sandbox Code Playgroud)

被视为

char disk[3] = {'D',':','\0'};
Run Code Online (Sandbox Code Playgroud)

在C++ 11及以上版本中

char* disk = "D:";
Run Code Online (Sandbox Code Playgroud)

是一个错误,因为字符串文字是类型的const char[],不能分配给char *.你可以将它分配给一个const char *.


Som*_*ude 5

字符串文字实际上是只读的,以零结尾的字符数组,并且使用字符串文字为您提供指向数组中第一个字符的指针.

所以在第二个例子中

char* disk = "D:";
Run Code Online (Sandbox Code Playgroud)

初始化disk为指向三个字符数组的第一个字符.


在我上面的第一段中注意到,我说字符串文字是只读数组,这意味着有一个简单的char*指向这个数组可能会让你认为可以修改这个数组当它不是(试图修改字符串文字的线索)到未定义行为).这是const char*通常使用的原因:

const char* disk = "D:";
Run Code Online (Sandbox Code Playgroud)

从C++ 11开始,不使用a实际上是一个错误const char*,通过大多数编译器仍然只是警告它而不是产生错误.