关于数组指针的一个疑问
最近看到了数组指针,测试一段代码的时候有一些疑问,所以想来这里和大家交流一下,麻烦大家帮忙看看,是什么原因。
代码如下:
- C/C++ code
#include<iostream>#include<cstdio>using namespace std;int main(void){ static int a[2]={1,2}; int p=5,p2=6,*page,*page2; int Test[2][3] = {{1,2,3},{4,5,6}};//测试二维数组 int Test2[3] = {1,2,3};//测试数组 page = &p; page2 = &p2; int (*A)[3],(*B)[3];//数组指针 A = &Test[1]; B = &Test2; cout<<*page<<endl; cout<<(*A)[0]<<(*A)[1]<<(*A)[2]<<endl; //cout<<(*A)[3]<<(*A)[4]<<(*A)[5]<<(*A)[6]<<endl; //cout<<(*B)[0]<<(*B)[1]<<(*B)[2]<<endl; cout<<(*B)[3]<<endl; //cout<<(*B)[4]<<(*B)[5]<<(*B)[6]<<endl; return 0;}
加注释的是我后来测试的,我说说我的疑惑,题目int (*A)[3],(*B)[3];定义了两个数组指针,
然后A = &Test[1];将A指向Test数组的第二行,
输出cout<<(*A)[0]<<(*A)[1]<<(*A)[2]<<endl;这一句应该输出4 5 6也没有错,
但是为什么我后面加上cout<<(*A)[3]<<(*A)[4]<<(*A)[5]<<(*A)[6]<<endl;这一句还能够编译通过呢,
输出是1 2 3 5这是为什么呢,
同理B指向数组Test2,Test2中一共有三个元素,输出(*B)[3]不是已经越界了吗,
但cout<<(*B)[3]<<endl;这一句却输出5,
而且cout<<(*B)[4]<<(*B)[5]<<(*B)[6]<<endl;这一句的(*B)[4]输出6,
后面的两个输出(*B)[5]和(*B)[6]才显示错误(是很小的负数),
我很不明白,请知道的帮忙解答一下。
[解决办法]
(*A)[3]开始也已经越界了,只不过编译的时候分配内存正好是Test[2][3],Test2[3],p,p2的顺序而已
也就是说,(*A)[3]实际上读到的是Test2[0],(*A)[6]读到的是p,(*B)[3]同理,(*B)[5]后面就正好没有数据了就错误了,这种未定义的行为出现任何结果都有可能
[解决办法]
http://blog.csdn.net/supermegaboy/article/details/4855000 这篇博文有你需要的答案,希望认真看完.
[解决办法]
[] 运算发生在运行时,编译器没有办法在编译期报警,所以能通过编译.
[解决办法]
第一个问题:栈上内存的分配是从高到低 Test越界过后得出的结果只是你内存中遗留下的结果,每个人的机子测出的都不一样,不可能是又回到你数组定义的地方输出原数据。
第二个问题,因为Test2数组是低地址并且与Test是连续分配的,也就是说Test2后面跟着Test,所以越界后会访问到Test的数据。至于什么时候报错我想应该是编译器说得算吧 我是无法理解。
[解决办法]
VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”
这辈子不看内存地址和内存值;只画链表、指针示意图,画堆栈示意图,画各种示意图,甚至自己没画过而只看过书上的图……能从本质上理解指针、理解函数参数传递吗?本人深表怀疑!
这辈子不种麦不收麦不将麦粒拿去磨面;只吃馒头、吃面条、吃面包、……甚至从没看过别人怎么蒸馒头,压面条,烤面包,……能从本质上理解面粉、理解面食吗?本人深表怀疑!!
提醒:
“学习用汇编语言写程序”
和
“VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
想要从本质上理解C指针,必须学习C和汇编的对应关系。”
不是一回事!
不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!
有人说一套做一套,你相信他说的还是相信他做的?
其实严格来说这个世界上古往今来所有人都是说一套做一套,不是吗?
不要写连自己也预测不了结果的代码!