结构体中定义未明长度数组的问题-C++
代码如下:
#include<iostream>
using namespace std;
struct cnode
{
cnode(){}
cnode(char pt[]){strcpy(p,pt);}
char p[];
};
int main(void)
{
cnode xyx("wang");
cout<<sizeof(xyx)<<" "<<sizeof(cnode)<<endl;
xyx.p[3]='4';
cout<<xyx.p<<endl;
return(0);
}
请问为什么两个sizeof返回的值都是1?,char p[]是属于什么类型的,指针?字符?
感觉两种解释都不怎么合理呀?而且如果char p[]变成char* p;的话系统是会中断的,好像是因为"wang"放在常量区。求大牛解释啊。
[最优解释]
char a[2]; // 毫无疑问是个数组,两个元素
a 表示该数组首元素地址,该地址存放首元素,在你的例子("wang"),应该是字符 'w'
第二个字符,则是 'a'。其它字符越界了
cnode 类之含 char a[2]; 则sizeof 就是2
如果你换成char *p; 那么 sizeof 是4,因为指针占4字节,用于保存一个地址。在你的例子里,你无法知道该地址在哪里。如果具体地,是VS的默认DEBUG的话,由于栈填充为0xCCCCCCCC,p就指向0xCCCCCCCC,因为该地址用户不可访问,所以必错无疑
[其他解释]
我觉得这里涉及了3个问题:
1.char p[]到底是几个元素的数组.
编译以上代码的时候,我的编译器发出C4200的警告.
搜索C4200
http://msdn.microsoft.com/en-us/library/79wf64bc.aspx
从上面错误反馈可以得知,p是一个长度为0的数组,也就是p是空的,不占任何空间
2.既然p不占任何空间,为什么sizeof( cnode )为1 ?
参考<<effecitve c++ 3rd>>,第39条 [use private inheritance judiciously]中的一句话
"an Empty data member requires memory. With most compilers, sizeof(Empty) is 1, because C++'s edict against zero-size freestanding objects is typically satisfied by the silent insertion of a char into "empty" objects."
大致就是大多数编译器对待独立的空数据对象时,通常会插入一个char,所以sizeof(char)是1
3.既然cnode大小为1,为什么可以修改p[3]的值?
在我的平台上,甚至可以修改p[30]的值.微软编译器可能不怎么阻止溢出,所以能否访问p[n]的值完全是操作平台的责任,因为在我的平台上,p[30]仍然是栈空间的一部分,所以操作系统允许我修改p[30]的值,当修改p[3000]的时候,数据已经不再是我的程序划分到空间,所以系统中断了程序.
[其他解释]
char p[];//字符数组,大小编译器确定,你说sizeof(cnode)为1那么它相当于char p[1];
至于xyz的大小肯定跟sizeof(cnode)一样。
再者,cnode(char pt[]){strcpy(p,pt);}是不安全的,strcpy是不管你p后面有多少合法的内存的。
[其他解释]
1.char p[]肯定是char的数组类型.
2.为什么char p[]不会中断,而char* p会中断?
调试了下,发现p[]的地址和cnode对象地址都是一样的,栈上面的地址,所以赋值没有太大问题,尽管你已经溢出,处于未定义行为的状态中.操作系统允许你操作栈上的内存,毕竟这个内存块是你的程序通过提交合法分配到的.
而char* p,p因为你没初始化,p可能是很遥远的乱码地址,只要这个地址不是你的程序向操作系统成功提交的后得到的有访问权的地址,任何读写p操作系统都会中断你的程序.
[其他解释]
自己google 柔性数组成员。
------其他解决方案--------------------
p是数组啊。。。
你出发点是从错误操作那里的,也就是strcpy(p,pt);越界了。
我这里运行你的代码会死机,到xyx.p[3]='4';这一句,所以说那是不安全的
p[3]编译器会解析为*(p+3);你给它赋值,它自然按你的操作去做,至于挂不挂掉是另外一会事。
不挂的话,也就能正确输出。
[其他解释]
新手make
[其他解释]
char p[];//字符数组,大小不确定
可以给个确定的大小,比如char p[10]等
如果用char *p;的话可以在用这个此前 p = new char[10];然后把"wang"拷到p指向的内存中。
[其他解释]
不是,我是想知道,我定义在cnode结构体中的char p[]的p是什么类型的?因为我输出sizeof(cnode)和
输出sizeof(xyz)的值都是1,按理来说xyz是用"wang"初始化过了的对象,应该占5个字节才对呀,而且p是常量吗?如果p是常量应该只能用构造函数的参数初始化列表初始化才行的呀?
[其他解释]
该回复于2012-11-26 08:59:58被管理员删除
[其他解释]
求大牛呀~~
[其他解释]
额,还是不懂,而且我想知道 p是数组还是指针,而且它只有1个字节,按理来说应该是字符,但是为什么输出p又能把整个字符串输出呢?这么说它又应该是数组,可是数组就应该是5个字节呀?而且为什么p[3]可以改变?
[其他解释]
谢谢你的回答,那请问是不是每个程序在运行时操作系统都会为它分配 固定大小 的内存作为它的栈区并且记录位置,若是程序里面的操作想要改变 该栈区之外 的内存系统就会中断该程序?而且栈的存储结构是数组的形式?还是链表栈?请各位赐教啊。
[其他解释]
谢谢你的回答,那我写char a[2];显然操作系统会分配两个连续的字节分别存放a[0],和a[1],那这个a又是什么东西?它应该也是一个变量吧?而他能存放地址,按理来说是指向常地址的指针,但是为什么sizeof(a)输出的却是2而不是4呢?
[其他解释]
谢谢你的回复,原来那种形式的数组称之为柔性数组,刚才google了一下,学到了很多东西,那能不能解答一下11和12楼的问题呢?
[其他解释]
求解答11、12楼的问题呀~
[其他解释]
你这里例子根本不是柔性数组,只是有点像而已
柔性数组要求前面还有其它成员的
这里其实只是编译器的非标准扩展,换个编译器结果就可不同,不建议深究
------其他解决方案--------------------
是的。系统默认会分配固定大小的栈内存,满了就是所谓的栈溢出
改变栈以外的内存未必出错,改变不允许改变的内存则一定出错
栈一般是连续的一片内存,也就是你所谓“存储结构是数组的形式”。