我想了解指针、数组和字符串文字在 C++ 中的工作方式。
假设我们有下面这行代码:
const char* const letters[] = {"A+","A"};
如果我没理解错的话,这个声明将字母声明为指向常量字符的常量指针数组。根据我的理解,编译器实际上会将每个字符串文字转换为以空字符结尾的 char 数组,字母的每个元素实际上是指向该数组第一个元素的常量指针。
例如,letters[0]
实际上是指向“A+”的“A”的指针。然而
std::cout<< letters[0];
实际输出"A+"
到标准输出。怎么会这样?特别是因为 letters[0]
是常量指针吗?
我的第二个问题与上面的声明有关:如果字符串文字实际上是 const char 数组,那么为什么下面的代码行
const char* const letters[] = {{'A','+','\0'},{'A','\0'}};
抛出
error: braces around scalar initializer for type ‘const char* const’
const char* const letters[] = {{'A','+','\0'},{'A','\0'}};
^
谢谢!
最佳答案
标准规定,就您的程序而言,字符串文字表示为 const
的数组。静态存储持续时间的字符,尾随 '\0'
终结者。该标准未指定编译器如何实现此效果,仅指定您的程序可以以这种方式处理字符串文字。
因此,要么阻止修改字符串文字(例如,将字符串文字传递给期望 char *
的函数是可诊断的错误,代码将无法编译),要么 - 如果代码绕过类型系统修改任何字符在字符串文字中 - 涉及未定义的行为。
在您的示例中,letters[0]
类型为 const char *
, 并且其值等于字符串文字中第一个字符的地址 "A+"
.
std::cout
, 属于 std::ostream
类型, 有一个 operator<<()
接受 const char *
.此函数由语句 std::cout << letters[0]
调用并且该函数假定 const char *
指向以零结尾的数组 char
.它遍历该数组,单独输出每个字符,直到遇到结尾的 '\0'
。 (这不是输出)。
事实是,一个 const char *
表示指针指向 const char
,并不是不能更改指针(即 char * const
)。所以可以增加指针,但不能改变它指向的值。所以,如果我们这样做
const char *p = letters[0];
while (*p != '\0')
{
std::cout << *p;
++p;
}
循环遍历字符串文字 "A+"
的字符,分别打印每一个,并在到达 '\0'
时停止(上面产生相同的可观察输出 std::cout << letters[0]
)。
然而,在上面
*p = 'C';
不会编译,因为 p
的定义告诉编译器 *p
不能改变。但是,递增 p
仍然允许。
原因
const char* const letters [] = {{'A','+','\0'},{'A','\0'}};
不编译是因为数组初始化器不能用于初始化指针。例如;
const int *nums = {1,2,3}; // invalid
const * const int nums2 [] = {{1,2,3}, {4,5,6}}; // invalid
都是非法的。相反,需要定义数组,而不是指针。
const int nums[] = {1,2,3};
const int nums2[][3] = {{1,2,3}, {4,5,6}};
所有版本的 C 和 C++ 都禁止以这种方式初始化指针(或您的示例中的指针数组)。
从技术上讲,使用字符串文字来初始化指针的能力实际上是异常的,而不是禁止使用数组初始化指针。 C 引入字符串文字豁免的原因是历史性的(在 C 的早期,远在 K&R C 之前,字符串文字也不能用于初始化指针)。
关于c++ - 将字符串文字转换为 char 数组实际上在 C++ 中如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57645930/