C++中二位数组的指针到底该如何使用?

剑神 发布于 2013/11/30 23:14
阅读 643
收藏 0

今天做二位数组的时候偶然碰到的一个问题:

我写了如下代码:

int A[3][3]={{1,2,3},{4,5,6},{7,8,9}};

int *p1=A[0];
int **p2=(int**)A;
int t1=A[0][0];
int t2=p1[0];
int t3=**A;
int t4=*(*(A+1)+1);
int t5=(*(A+1))[1];
int t6=**p2;
int t7=*(*(p2+1)+1);
int t8=(*(p2+1))[1];

但是运行的时候发现到了这一行,程序直接崩溃了:

int t6=**p2;

注释掉这一行之后,运行下一行,程序还是崩溃了:

int t7=*(*(p2+1)+1);
注释掉这一行之后,运行下一行,程序依然崩溃:

int t8=(*(p2+1))[1];
当我进行调试的时候,发现如下:


注意红色框起来的地方的数值,这里调试的时候发现 A 表示的地址的值和 p2 表示的是一样的,但是很明显的除了这个是一样的其他的没有一个是一样的,对于指针的调用我个人认为我的表达式是没有问题的,但是为什么对于A能用而对于p2却用不了呢?

而且很显然,如果我对p2只做这样“ int *p3=*p2; ”的一次解引用,最后P3也不能再进行解引用操作了,运行的结果无非还是程序直接奔溃。


我想知道的是,p2A的所指地址的值一模一样,那为什么p2无法做像A一样的指针操作呢?

我所用的环境是VC6.0和VS2010,两个编译环境都是一样的,程序运行奔溃,调试也发现了类似的信息,请路过的大神指点迷津,小弟在此谢过了!



以下是问题补充:

@剑神:我换到Ubuntu下的Eclipse也是直接奔溃;换到Ubuntu的Anjuta编译虽然可以过,但是却不能对 t6、t7、t8进行使用 ,一旦使用也会直接奔溃。 (2013/11/30 23:42)
加载中
0
中山野鬼
中山野鬼

“p2A的所指地址的值一模一样” ,这个话是你自己说的,哈,可不是编译器和c语言标准说的。你自己理解错误。

 int **p2,我说过无数次,是一个空间,名字叫做p2,里面存的数据,用于指向其他空间,不过对其他空间的类型有要求。要求是,后者空间里面存放的仍然是个地址,那个地址将指向int类型的空间。

int a[][],是二维数组而已。a实际对应的地址并没有任何地方存储,仅表示一个连续的空间,可以被二维网格化。a直接等同于这个空间的首地址。

a和a[0],你转成整数是,如果他们数值上是否一样,你自己试试就知道。a,a[0],&(a[0][0])他们是否一样你也可以试试就知道。

再简单举个例子:

int *p1[3];
int **p2 = p1;
int a[3][3];
    p1[0] =&(a[0][0]);
    p1[1] =&(a[1][1]);
    p1[2] =&(a[2][2]);
    



你自己判断一下,p2[0],p2[1],p2[0][1],p2[2][0]是否和对应的a相同。


剑神
剑神
昨晚睡觉的时候我也仔细想了一下,发现确实应该是这样的。
0
m
mdsmqh
不是很懂,在书上看到这样一句话:多维数组转换而成的指针类应是指向第一个内层数组的指针。我觉得可能是A[3][3]为一个有结构的东西,也许在执行**A时,实际执行的就是*A,因为A和A【0】存储的都是A【0】【0】的地址,但**p2,系统将他视为指向int *的指针,所以实际会执行*A【0】【0】,而A【0】【0】是1,所以越界了。将int **p2=(int **)A;改为int (*p2)[3]=A;就没错误了!我也不是很明白,以上仅为个人意见,不对勿喷!
0
喵星人哦
喵星人哦
编译成二进制后根本没有二维数组,二维数组也好,一维数组也好,都是通过数组首地址加偏移实现的,理解这个再想想 
0
中山野鬼
中山野鬼

引用来自“阿汞”的答案

编译成二进制后根本没有二维数组,二维数组也好,一维数组也好,都是通过数组首地址加偏移实现的,理解这个再想想 
哈,这个是懂的人。。
剑神
剑神
我直接通过偏移量然后使用memcpy函数把地址里面的内容复制到一个int变量的内存里面就能用了。
0
剑神
剑神
Thank You All!
返回顶部
顶部