• 全部
  • 问答

字符串常量到底存在什么区了?

平凡的Coder 2013-04-26 08:59:11
void main()
{
char *p ="123456";
}
这个涉及到栈和常量内存区。

void main()
{
char a[] ="123456";
}
这个呢?这个涉及到哪些区呢?

...全文
1264 点赞 收藏 34
写回复
34 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
引用 29 楼 lm_whales 的回复:
[quote=引用 4 楼 dxy0613 的回复:] 那天看到一个好玩的代码:

int main()
{
    int i =0, k[10] = {0};
    for(;i <= 10; ++i)
    {
        k[i] = 0;
    }
}
额。忘记了。反正大概长这样,代码的意思是说,在声明的时候,因为栈的分配原因(先入后出),k[10]就是i的地址。然后i就会被修改成0,循环再次开始,就这样出现了一个死循环,哎。忘记了。上次看到的。没有抄下来,可能有错。
这个是有条件的 1)编译器顺序安排变量的地址(VC的增量连接会打乱顺序) 2)变量长度恰好和编译器当前对齐尺度一致。 3)编译器没有给变量额外安排空间(如VC Debug 版会在变量两边安排一些CC数据) [/quote] 嗯是的,上次我也测试过,一定没有试出网上那人说的效果。看完你的明白了。学习。
回复
赵4老师 2013-05-02
讨论之前请先观察
回复
lm_whales 2013-05-02
引用 4 楼 dxy0613 的回复:
那天看到一个好玩的代码:

int main()
{
    int i =0, k[10] = {0};
    for(;i <= 10; ++i)
    {
        k[i] = 0;
    }
}
额。忘记了。反正大概长这样,代码的意思是说,在声明的时候,因为栈的分配原因(先入后出),k[10]就是i的地址。然后i就会被修改成0,循环再次开始,就这样出现了一个死循环,哎。忘记了。上次看到的。没有抄下来,可能有错。
这个是有条件的 1)编译器顺序安排变量的地址(VC的增量连接会打乱顺序) 2)变量长度恰好和编译器当前对齐尺度一致。 3)编译器没有给变量额外安排空间(如VC Debug 版会在变量两边安排一些CC数据)
回复
lm_whales 2013-05-02
安排大量代码为数组一一赋值,是不合适的,除非常量比较短。 所以对于局部自动变量数组的初始化,应该会把常量存放在常量区或者数据区,然后初始化的时候,把常量搬到数组中(定义为数组); 如果是定义为字符串指针,则只要把常量的地址,赋值给指针就可以了。
回复
赵4老师 2013-05-02
对比22楼和23楼dumpbin的输出,可以看出Debug和Release版是不一样的。
回复
lm_whales 2013-05-02
不过自动变量存储在栈区,容易丢失,而每次函数调用必须重新初始化自动变量数组。 所以编译器,只有先把常量存储在,数据区或者常量区,才可以对数组进行初始化。 不然的话: 只有安排指令一个一个的给数组元素赋值,这无论是编译还是运行都是低效的行为。 只有较短的数组,才会这么处理。 数据区或者常量区的数据,由加载程序处理初始化,不损害,运行效率。
回复
lm_whales 2013-05-02
指针和数组的最大区别是,指针和数据分别占用不同的内存。 数组和数据占用同一内存,不需要额外的内存。 char *s= "123"; char ss[]="123"; &ss 和ss 是相同的地址只是类型不同。 &s和s是不同的地址,指针变量本身占有一份内存。数据也占有一份内存。
回复
lm_whales 2013-05-01
char *s="12345"; //VC debug 版常量区,release版数据区,数据区有一个指针,有两处一处字符串,一处指针,相同常量可能会共用同一数据。 char ss[]="12345"; //VC debug 版数据区,release版数据区,数据区有一个数组,只有一份。 有时常量相同,也会公用同一数组。 int main() { char *ts="12345"; //VC debug 版常量区,release版数据区,栈上只有一个指针。 char tss[]="12335"; //VC debug 版数据区,release版数据区,栈上只有一个数组。 。。。。。 return 0; }
回复
池塘码农 2013-05-01
http://blog.csdn.net/dw903632958/article/details/8873287
可以看看
回复
平凡的Coder 2013-05-01
引用 25 楼 lm_whales 的回复:
char *s="12345"; //VC debug 版常量区,release版数据区,数据区有一个指针,有两处一处字符串,一处指针,相同常量可能会共用同一数据。 char ss[]="12345"; //VC debug 版数据区,release版数据区,数据区有一个数组,只有一份。 有时常量相同,也会公用同一数组。 int main() { char *ts="12345"; //VC debug 版常量区,release版数据区,栈上只有一个指针。 char tss[]="12335"; //VC debug 版数据区,release版数据区,栈上只有一个数组。 。。。。。 return 0; }
char tss[]="12335" 我觉得24楼可能是对的,Debug版下,常量区 和 栈区又有一份 Release版本我没有试过。
回复
xiaohuh421 2013-04-27
char *p = "123456"; 00C6A8DD mov dword ptr [ebp-18h],offset string "123456" (0CB6940h) char a[] = "123456"; 00C6A8E4 mov eax,dword ptr [string "123456" (0CB6940h)] 00C6A8E9 mov dword ptr [ebp-28h],eax 00C6A8EC mov cx,word ptr ds:[0CB6944h] 00C6A8F3 mov word ptr [ebp-24h],cx 00C6A8F7 mov dl,byte ptr ds:[0CB6946h] 00C6A8FD mov byte ptr [ebp-22h],dl char b[7] = "123456"; 00C6A900 mov eax,dword ptr [string "123456" (0CB6940h)] 00C6A905 mov dword ptr [ebp-38h],eax 00C6A908 mov cx,word ptr ds:[0CB6944h] 00C6A90F mov word ptr [ebp-34h],cx 00C6A913 mov dl,byte ptr ds:[0CB6946h] 00C6A919 mov byte ptr [ebp-32h],dl 这段汇编代码应该能解释一二了. 至少可以看到 char a[] = "123456" 等价于 char a[7] = "123456".
回复
池塘码农 2013-04-27
楼上各种有经验,受教了
回复
xiaohuh421 2013-04-27
char a[] ="123456"; 这个东西会被编译器变成 char a[7] = "123456" 这样你就能清楚放在哪里了吧. 实际上相当于是一个动态数组, 但是是在编译期决定其大小. char a[] ="123456"; 就相当于, 申请了一个数组, 然后初始化为 123456 具体细节, 可以查看反汇编代码.
回复
平凡的Coder 2013-04-27
int m=1;
int i =0;
int k[10] = {0};
printf("&m=%d\n",&m);
printf("&i=%d\n",&i);
printf("&k[0]=%d\n",&k[0]);
printf("&k[9]=%d\n",&k[9]);
printf("&k[10]=%d\n",&k[10]);

for(;i <= 10; ++i)
{
k[i] = 0;
}
printf("HelloWorld!\n");


结果可以说明4楼的问题了
回复
lin5161678 2013-04-27
引用 4 楼 dxy0613 的回复:
那天看到一个好玩的代码:

int main()
{
    int i =0, k[10] = {0};
    for(;i <= 10; ++i)
    {
        k[i] = 0;
    }
}
额。忘记了。反正大概长这样,代码的意思是说,在声明的时候,因为栈的分配原因(先入后出),k[10]就是i的地址。然后i就会被修改成0,循环再次开始,就这样出现了一个死循环,哎。忘记了。上次看到的。没有抄下来,可能有错。
UB结果是不确定的 未必能修改i的值
回复
nirvana_newbie 2013-04-27
引用 13 楼 xgmiao 的回复:
[quote=引用 11 楼 nirvana_newbie 的回复:] char a[] ="123456"; 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。常量字符串"123456"是被存放在静态存储区。 楼主糊涂的是为什么a[0]可修改,p[0]不可修改。 如果把上面的代码这样写,我想你就好理解了:
char *s="123456";
char *p = s;
char a[6];
for (int i=0;i!=6;i++)
{
     a[i] = s[i];
}
a[6] = '\0';
a中存放的是s的副本,p存放的是s的首地址。a[0]修改了,是修改的副本的值,s的值并不变。所以不会出错。 p[0]修改了,是修改常量s里的值,不可以修改,所以出错。
照你的意思是, void main() { char a[]="1234"; } 既涉及到栈 又涉及到常量区? 但是华清远见的一个老师说,数组时,它是以立即数的形式直接存的,也就是说不会存在常量区,具体请看http://www.embedu.org/Column/Column540.htm [/quote] 查阅了资料,我的答案是错误的。 char a[]="123456";是存放在栈上的。 具体的原因我也不清楚。这得去看数组和指针的实现机制了吧。等我找到答案再告诉你。
回复
平凡的Coder 2013-04-27
引用 11 楼 nirvana_newbie 的回复:
char a[] ="123456"; 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。常量字符串"123456"是被存放在静态存储区。 楼主糊涂的是为什么a[0]可修改,p[0]不可修改。 如果把上面的代码这样写,我想你就好理解了:
char *s="123456";
char *p = s;
char a[6];
for (int i=0;i!=6;i++)
{
     a[i] = s[i];
}
a[6] = '\0';
a中存放的是s的副本,p存放的是s的首地址。a[0]修改了,是修改的副本的值,s的值并不变。所以不会出错。 p[0]修改了,是修改常量s里的值,不可以修改,所以出错。
照你的意思是, void main() { char a[]="1234"; } 既涉及到栈 又涉及到常量区? 但是华清远见的一个老师说,数组时,它是以立即数的形式直接存的,也就是说不会存在常量区,具体请看http://www.embedu.org/Column/Column540.htm
回复
看到了4,7楼, 我也试了一下.学习一下.
道理明白了,不过不同编译器情况不同吧? 我这边用VC2010, 要到K[12]才会使 i 和K[12]地址一样,才会死循环.
不过话说, 定义数组k[10], 元素k[10]以后都是没有定义的,正常不会有这种用法吧.

#include <iostream>

int main()
{
int i =0,k[10] = {0};
printf("&i=%d\n",&i);
printf("&k[0]=%d\n",&k[0]);
printf("&k[9]=%d\n",&k[9]);
printf("&k[10]=%d\n",&k[10]);
printf("&k[12]=%d\n",&k[12]);

for(;i <= 12; ++i)
{
k[i] = 0;
}
printf("HelloWorld!\n");
return 0;

}


回复
nirvana_newbie 2013-04-27
char a[] ="123456"; 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。常量字符串"123456"是被存放在静态存储区。 楼主糊涂的是为什么a[0]可修改,p[0]不可修改。 如果把上面的代码这样写,我想你就好理解了:
char *s="123456";
char *p = s;
char a[6];
for (int i=0;i!=6;i++)
{
     a[i] = s[i];
}
a[6] = '\0';
a中存放的是s的副本,p存放的是s的首地址。a[0]修改了,是修改的副本的值,s的值并不变。所以不会出错。 p[0]修改了,是修改常量s里的值,不可以修改,所以出错。
回复
平凡的Coder 2013-04-27
引用 6 楼 ZLhy_ 的回复:
void main() { char a[] ="123456"; } a是栈区的一个变量,后面的字符串字面值(就是字符串常量)是在常量区存放的,而且你这样子声明是有隐含的危险的,因为后面是常量,但是你的数组却是一个普通的non-const数组,当你执行a[0] = 'A';时,编译是可以通过的,但是运行期会抛错,常量不允许改的错误。所以你要const char a[] = "123456";这样子才合适。
void main() { char *p="12345"; p[1]='a'; } 这样肯定是有错的,因为p指向的是常量区,不准修改。p是在栈中的,“12345”在常量区 而对于 void main() { char a[]="12345"; a[0] = 'A'; } 这个肯定是没有错的,至于为什么没有错,我觉得有可能此时“12345”并不是存在常量区,所以能改. 看http://www.embedu.org/Column/Column540.htm 他好像就是说他该字符串常量是存在栈中的。 还有一种说法是,“12345”是存在常量区,但是在栈中有它的一份拷贝,所以a[0]='A'相当于改变的是它的拷贝。这里就是这么说的http://wenku.baidu.com/view/ea39b8000740be1e650e9a3e.html 所以我就困惑了,它到底是怎么存的。
回复
发帖
C++ 语言
创建于2007-09-28

5.9w+

社区成员

C++ 语言相关问题讨论,技术干货分享,前沿动态等
申请成为版主
帖子事件
创建了帖子
2013-04-26 08:59
社区公告
暂无公告