繁体   English   中英

从字符串文字初始化char数组时会发生什么?

[英]What happens when a char array gets initialized from a string literal?

据我了解,以下代码的工作原理如下:

char* cptr = "Hello World";

“Hello World”存在于程序内存的.rodata部分。 字符串文字"Hello World"返回一个指向字符串基址的指针,或者所谓的“数组”中第一个元素的地址,因为字符在内存中按顺序排列,它将是'H' 。 这是我的小图,因为我可视化存储在内存中的字符串文字:

0x4 : 'H'
0x5 : 'e'
0x6 : 'l'
0x6 : 'l'
0x7 : 'o'
0x8 : ' '
0x9 : 'W'
0xa : 'o'
0xb : 'r'
0xc : 'l'
0xd : 'd'
0xe : '\0'

所以上面的声明变成:

char* cptr = 0x4;

现在cptr指向字符串文字。 我只是在编写地址。

0xa1 : 0x4

现在这段代码如何工作?

char cString[] = "Hello World";

我假设与前一种情况一样, "Hello World"也会降级为“H”和0x4的地址。

char cString[] = 0x4;

我在使用char数组的初始化时读取=作为重载赋值运算符。 据我所知,仅在C字符串的初始化时,它会将char-by-char从给定的基址开始复制到C字符串中,直到它在复制的最后一个char时命中'\\ 0'。 它还为所有字符分配足够的内存。 因为重载运算符实际上只是函数,我假设它的内部实现类似于strcpy()

我希望有一位经验丰富的C程序员确认我对这段代码如何工作的假设。 这是我对字符串文字中的字符复制到其中后的C字符串的可视化:

0xb4 : 'H'
0xb5 : 'e'
0xb6 : 'l'
0xb6 : 'l'
0xb7 : 'o'
0xb8 : ' '
0xb9 : 'W'
0xba : 'o'
0xbb : 'r'
0xbc : 'l'
0xbd : 'd'
0xbe : '\0'

再一次,地址是任意的,重点是堆栈中的C字符串与内存中.rodata部分中的字符串文字不同。

我想做什么? 我正在尝试使用char指针暂时保存字符串文字的基址,并使用相同的char指针(字符串文字的基址)来初始化C字符串。

char* cptr = "Hello World";
char cString[] = cptr;

我假设"Hello World"计算其基址0x4 所以这段代码应该是这样的:

char* cptr = 0x4;
char cString[] = 0x4;

我认为它应该与char cString[] = "Hello World";没有什么不同char cString[] = "Hello World"; 因为“Hello World”评估它的基地址,那就是存储在char指针中的内容!

但是,gcc给了我一个错误:

error: invalid initializer
char cString[] = cptr;
                 ^
  1. 为什么不能使用char指针作为临时占位符来存储字符串文字的基址?
  2. 这段代码是如何工作的? 我的假设是否正确?
  3. 在代码中使用字符串文字是否将基址返回到字符存储在内存中的“数组”?

您对内存布局的理解或多或少是正确的。 但是你遇到的问题是C中的初始化语义之一。

此处声明中的=符号不是赋值运算符。 相反,它是语法,为正在实例化的变量指定初始化程序。 在一般情况下, T x = y; T x; x = y; T x; x = y;

有一种语言规则,可以从字符串文字初始化字符数组。 (在此上下文中,字符串文字不会“评估为其基址”)。 没有语言规则可以从指向要复制到数组中的元素的指针初始化数组。

为什么这样的规则? “历史原因”。

我假设与前一种情况一样, "Hello World"也会降级为'H'0x4的地址。

不是真的: cString[]在内存中获取一个全新的地址。 编译器为其分配12个char ,并使用"Hello World"字符串文字的内容初始化它们。

我假设"Hello World"计算其基址0x4 在代码中使用字符串文字是否将基址返回到字符存储在内存中的“数组”?

cString可以在以后转换char* ,产生其基地址,但它仍然是常规上下文中的数组。 特别是,如果调用sizeof(cString)您将获得数组的大小,而不是指针的大小。

为什么不能使用char指针作为临时占位符来存储字符串文字的基址?

您可以。 但是,一旦将字符串文字赋给char * ,它就会停止为字符串文字,至少就编译器而言。 它变成了一个char *指针,与其他char *指针没有区别。

请注意,现代C编译器将相同的字符串文字组合为优化,因此如果您编写

#define HELLO_WORLD "Hello World"
...
char* cptr = HELLO_WORLD;
char cString[] = HELLO_WORLD;

并且打开优化,编译器将消除字符串文字的重复副本。

第二个定义char cString[] = "Hello World"; 是这个等价定义的简写:

char cString[12] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '\0' };

如果此定义作为全局作用域或使用static存储发生,则cString将位于.data段中,其中包含可执行映像中的初始内容。 如果它不具有自动存储功能的范围,编译器将为该数组分配自动存储(保留堆栈帧上的空间或等效物)并生成代码以在运行时执行初始化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM