void f(int **a)
{
cout << a[0][0] << endl;
cout << a[1][0] << endl;
}
int main()
{
{
int t1[2];
int tt[2][2];
tt[0][0] = 1;
tt[0][1] = 2;
tt[1][0] = 3;
tt[1][1] = 4;
int **ttp = new int*[2];
for(int i = 0; i < 2; ++i)
{
ttp[i] = new int[2];
for(int j = 0; j < 2; ++j)
{
ttp[i][j] = tt[i][j];
}
}
// 此处强转,在f中访问[0][0]元素时会出错。
// 传入ttp则是好的。
// 错误提示:test.exe 中的 0x00ee17bd 处有未经处理的异常: 0xC0000005: 读取位置 0x00000001 时发生访问冲突
f((int**)tt);
}
return 0;
2 回答
RISEBY
TA贡献1856条经验 获得超5个赞
楼主是初学C语言吗?如果是初学者能够触探到这样的问题我认为是大有前途的。
都说C语言最难理解的是指针,而指向指针的指针和二维数组又是最容易搞混的地方,因为二者都通过在前面加两个*来取值。但二者是完全不同的类型,运算法则完全不一样。
楼主做强制转换虽然骗过了编译器,但接下来执行f里面代码的时候,a[0][0]是按照*(*(a+0))的方式展开执行的,注意a的类型是指向指针的指针而不是二维数组名,所以括号里面的*(a+0)的执行结果就是1,接下来再执行*1,这个时候把1当作一个地址,试图把这个地址里面的数据取出来,现在可以明白了,如果不报错,取到的并非你预期的数据,是一个不可预料的值。之所以报错是因为运行环境检测到1这个地址不是本程序有权访问的(是操作系统的保留内存),所以就报错了,这里其实就形成了一个野指针。
而假如a的类型是二维数组名,a[0][0]也是按照*(*(a+0))的方式执行的,但此时应注意a是一个行指针,指向二维数据的第一行,a+0=a还是指向二维数据的第一行(a+1就表示指向第二行的行指针),*(a+0)只不过是把行指针转成了列指针(注意a+0和*(a+0)的值是相同的,只不过类型不同,你可以打印出来看下),接下来再执行最外层的*就是取第一行第一列的值了。
由此可见指向指针的指针和二维数组名取值的运算法则是完全不一样的,请楼主仔细体会。
另外要补充说明的是,二维数组从物理上来说也是一段连续的内存空间,而不应把它想象成
装着多个一维数组的数组。
- 2 回答
- 0 关注
- 759 浏览
添加回答
举报
0/150
提交
取消