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

问题描述 投票:4回答:3

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

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";没有什么不同,因为“Hello World”评估它的基地址,那就是存储在char指针中的内容!

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

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

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

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

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

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


3
投票

我假设在前面的情况下"Hello World"也降级到'H'0x4的地址。

不是真的:cString[]在内存中获得了一个全新的地址。编译器为其分配12个chars,并使用"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;

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


3
投票

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.