问题描述
我正在浏览这个 QA,据说 char
数组在用字符串文字初始化时会导致两次内存分配,一个用于变量,另一个用于字符串文字。
我写了下面的程序来看看内存是如何分配的。
#include <stdio.h>
#include <string.h>
int main()
{
char a[] = "123454321";
printf("a =%p and &a = %p\n",a,&a);
for(int i = 0; i< strlen(a); i++)
printf("&a[%d] =%p and a[%d] = %c\n",i,&a[i],a[i]);
return 0;
}
输出为:
a =0x7ffdae87858e and &a = 0x7ffdae87858e
&a[0] =0x7ffdae87858e and a[0] = 1
&a[1] =0x7ffdae87858f and a[1] = 2
&a[2] =0x7ffdae878590 and a[2] = 3
&a[3] =0x7ffdae878591 and a[3] = 4
&a[4] =0x7ffdae878592 and a[4] = 5
&a[5] =0x7ffdae878593 and a[5] = 4
&a[6] =0x7ffdae878594 and a[6] = 3
&a[7] =0x7ffdae878595 and a[7] = 2
&a[8] =0x7ffdae878596 and a[8] = 1
从输出来看,我们没有为数组和字符串文字提供两个单独的内存位置。
如果我们有单独的数组和字符串字面量内存,有没有什么办法可以证明在这种情况下数组a
和字符串字面量是分开存储的?
克隆链接:https://onlinegdb.com/HkJhdSHyd
解决方法
char a[] = "123454321";
从技术上讲,字符串文字 "123454321"
不需要存储在任何地方。所需要的只是在输入 a[]
时用正确的值初始化 main
。无论是通过从某个静态只读内存位置复制字符串来完成,还是运行以其他方式填充它的代码,都不是标准规定的。
就标准而言,编译器发出与以下等效的代码以初始化 a[]
是完全可以接受的:
char a[10];
for(int n = 0; n <= 4; n++)
a[n] = a[8-n] = '1' + n;
a[9] = '\0';
事实上,至少有一个编译器 (gcc) 通过自定义代码初始化 a[]
,而不是存储和复制文字字符串。
mov DWORD PTR [ebp-22],875770417 ; = 0x34333231 = '1','2','3','4'
mov DWORD PTR [ebp-18],842216501 ; = 0x32333435 = '5`,'4','2'
mov WORD PTR [ebp-14],49 ; = 0x31 = '1','\0'
,
您完全误解了问题和答案。问题是关于 initializer 字符串除了实际数组之外是否还消耗内存。现在的问题是,你不能观察初始化字符串。
就像有两张纸。柜子里有一张用圆珠笔写的123454321。桌子上的一个 - 最初是空的。然后另一个人来了,从壁橱里拿出床单,读上面的文字,然后用铅笔写在桌子上的床单上。然后把纸放回柜子里。
现在你正在看桌子上的那张纸说:“很明显,文本 123454321 没有在这张纸上写过两次,所以他们怎么说有两份?”
,你不能证明有两个存储,因为你只有一个。
编译器认为你想要一个用一些字符和 '\0' 初始化的 char 数组,所以它会这样做。它不需要将字符串文字存储在其他地方。
由于这个原因,这不会编译。
#include <stdio.h>
#include <string.h>
char *p = "123454321";
int main()
{
char a[] = p;
printf("a =%p and &a = %p\n",a,&a);
for(int i = 0; i< strlen(a); i++)
printf("&a[%d] =%p and a[%d] = %c\n",i,&a[i],a[i]);
return 0;
}
,
可以通过如下修改代码来证明:
int main()
{
for (int i = 0; i < 2; ++i)
{
char a[] = "123454321";
printf("a = %s\n",a);
a[3] = 'x';
a[5] = 'y';
printf("a = %s\n",a);
}
}
输出:
a = 123454321
a = 123x5y321
a = 123454321
a = 123x5y321
修改后我们得到了原来的字符串,所以原来的字符串一定是存放在我们修改的地方以外的地方。