字符串文字到 char 数组的转换如何在C++中实际工作

How does conversion of string literals to char arrays actually work in C++?

本文关键字:C++ 实际工作 转换 文字 char 数组 字符串      更新时间:2023-10-16

我试图了解指针,数组和字符串文字如何在C++中工作。

假设我们有以下代码行:

const char* const letters[] = {"A+","A"};

如果我理解正确,此声明声明字母是指向常量字符的常量指针数组。根据我的理解,编译器实际上会将每个字符串文字转换为以 null 结尾的 char 数组,并且每个字母元素实际上是指向该数组第一个元素的常量指针。

因此,例如,letters[0]实际上是指向"A+"的"A"的指针。然而

std::cout<< letters[0];

实际输出"A+"到标准输出。这怎么可能?特别是因为letters[0]是一个恒定的指针?

我的第二个问题与上面的声明有关:如果字符串文字实际上是 const char 数组,那么为什么下面的代码行

const char* const letters[] = {{'A','+',''},{'A',''}};

抛出

error: braces around scalar initializer for type ‘const char* const’ const char* const letters[] = {{'A','+',''},{'A',''}}; ^

谢谢!

该标准指定字符串文本 - 就您的程序而言 - 表示为静态存储持续时间的const字符数组,带有尾随''终止符。 该标准没有指定编译器如何实现此效果,只是您的程序可以以这种方式处理字符串文字。

因此,要么阻止修改字符串文字(例如,将字符串文字传递给期望char *的函数是一个可诊断的错误,并且代码将无法编译),要么 - 如果代码围绕类型系统修改字符串文字中的任何字符 - 涉及未定义的行为。

在您的示例中,letters[0]的类型为const char *,其值等于字符串文本"A+"中第一个字符的地址。

std::cout,属于std::ostream型,有一个接受const char *operator<<()。 此函数由语句std::cout << letters[0]调用,该函数假定const char *点为零终止的char数组。 它遍历该数组,单独输出每个字符,直到遇到尾随''(不输出)。

问题是,const char *意味着指针指向const char,而不是指针不能更改(那将是char * const)。 因此,可以增加指针,但不能更改它指向的值。 所以,如果我们这样做

const char *p = letters[0];
while (*p != '')
{
std::cout << *p;
++p;
}

它循环访问字符串文字"A+"的字符,单独打印每个字符,并在到达''时停止(上面产生相同的可观察输出std::cout << letters[0])。

但是,在上面

*p = 'C';

不会编译,因为p的定义告诉编译器*p无法更改。 但是,仍允许递增p

原因

const char* const letters [] = {{'A','+',''},{'A',''}};

不编译的是数组初始化器不能用于初始化指针。 例如;

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之前,字符串文字也不能用于初始化指针)。

至于你的第一个问题,letters[0]的类型是const char * const.这是指向字符的指针,但不是字符本身。当将指向字符的指针传递给std::cout时,它会将其视为以 NUL 结尾的 C 字符串,并写出从内存指向的开头到遇到 NUL 字节的所有字符。所以这就是为什么输出将是A+.您可以通过编写以下内容自行传递第一个字符串的第一个字符:

std::cout << letters[0][0];

指针和/或 C 字符串本身是 const 的事实在这里并不重要,因为没有任何东西写入它们。

至于你的第二个问题,const char * const声明了一个数组,但你在该语句的右侧提供了一个嵌套数组。如果你真的想要两个字符数组,请写:

const char *const letters[] = {{'A', '+', ''}, {'A', ''}};

这等于你的代码形式第一个问题。或者,如果您想要单个阵列:

const char *const letters = {'A', '+', '', 'A', ''};

该行等于:

const char *const letters = "A+A";