C++-二维数组与二级指针-为何二维数组不可以作为函数实参进行转化

C++-二维数组与二级指针-为何二维数组不可以作为函数实参进行转化,第1张

背景:

在C++编程时,经常会遇到需要把二维数组传给函数参数,而我们的二维数组可能是堆分配的二级指针或者直接声明规模的二维数组。


这个时候如果函数的形参与该数组的形式不同,就会造成编译结果偏差。


解决方法:

首先,先不说为什么,咱先给出解决方式,那就是把形式对准就好了。



(1)如果声明int a[4][2],那函数的参数就是void b(int ( *a)[2])
(2)如果声明int **a,a=new int *[4],for(int i=0;i<4;i++) { a[i]=new int[2];},那函数的参数就是void b(int **b);

问题:为什么二维数组不可以传给函数参数中的二级指针呢?

该问题我们可以在以下几个方面进行解释:
1.二维数组和二级指针在内存中区别是什么?
2.如果二维数组传给函数中的二级指针会怎么样?

回答:

首先,我们先解释一个许多同学可能会问的问题,那就是:
1.变量的变量名存放在哪?
**答:**变量名只是我们用于编程时需要用到的。


在经过汇编之后,变量名也随之转化为地址,到此时,并不存在变量名。


也就是说在内存中无需太过注意变量名存放在哪。


2.地址,地址的地址,地址的地址的地址,到底是个什么情况?
答:
相信很多同学如果想到这里,可能会有所疑问,如果可以无限下去,那么岂不是所有内存都成地址了?其实不是,按我的理解,其实除了一些特定形式的变量外,不存在地址的地址。


因为一个单元就是一个地址,单元通过数据线传输,而单元所处的位置通过地址线定位,那么就意味着,地址的值并不是某个内存单元的值,所有就不存在地址的地址。


也就是说,当我们声明int a=0,那么存在a的地址&a,但是&(&a)就会出错,除非我们声明int *b=&a;但是这样我们就相当于把a的地址值存到另一个内存单元b里,这只是换个地方求地址,本质没有改变。


3.但是在二维数组中,就存在这么一个现象:地址等于存储地址的变量的地址
答:
我们声明一个int a[5][2]={0},那么就会有&a[0][0]=a[0]=&a[0]=a=&a。


那么这种情况呢按我理解只是二维数组的一个编译结果,是针对于二维数组连续分配的特殊情况的一个方式。


这在二级指针中是不同的,所以这个现象是直接声明的二维数组和二级指针的一个区别。


4.二维数组和二级指针在内存中区别是什么?
答:
二维数组直接声明:
例如int A[5][2],在内存中直接生成的一个连续的分配空间,如图,A[5][2]在内存会被当做是一个连续串,我们用a[0~9]表示。


在这种情况下,没有其他多余的变量。




二级指针:
例如声明
int *p=new int[5];
for(int i=0;i<5;i++)
{
p[i]=new int[5];
}
在堆中,数组并没有像直接声明长度的二维数组那样连续分配。


而是首先有一个变量p,在堆中开辟一个int[5]大小的数组,
变量p的值就是p[0]的地址。


而后对每一个p[i],0<=i<5,会再次申请堆中的一个int[5]大小的分配。


也就是说,二维数组的堆分配空间不连续。


是以地址链接为主要方式。


到这里就大概明白直接声明长度的二维数组和二级指针堆分配的二维数组的区别了。



区别:
(1).地址空间连续与不连续的区别。



(2).计算机在访问两种二维数组的时候, *** 作必然不同

5.如果二维数组传给函数中的二级指针会怎么样?
答:
假设我们把二维数组传送给函数参数中的二级指针。



即有int a[4][2];函数void b(int **p);
我们运行b(a),会怎样。



我们可以确定,编译不通过。


但我们用某种办法让其通过。



比如int *t=a[0];运行b(&t);这种情况编译通过,但结果基本错误。



理由如下:
假设把二位数组传送给函数中的二级指针。


那么函数会把二维数组当作二级指针来 *** 作。


但是二维数组和二级指针的内存分布是不同的,这就导致许多 *** 纵是必然出错的。



举个例子。



我们需要运行a[0][0]=0;
但函数的 *** 作是这样的。


默认a的值是a[0]的地址,取得a[0],在二级指针中,a[0]的值是a[0][0]的地址,因此还需要再次取值才可以取得a[0][0],然而在直接声明长度的二维数组中,&a[0][0]=a[0]=&a[0]=a=&a,这就说明对a所存的地址进行取值即可得到a[0][0]。


再次进行寻址取值就会把a[0][0]的值当作地址去取值,所以就会出错。



在这里可能有同学会有疑问,那就是自己使用 *a进行取值时,发现 *a并不是a[0][0]的值,这是因为编译的问题。


我们知道高级语言在汇编称汇编语言后,各个变量基本都是编程地址值的。


也就是说,对地址值进行寻址必然可以取到该单元的数值,但二维数组有其编译的特殊规律,在编译 *a后,为了实现高级语言中的二维数组的语法,自然不是简单取值。


所以这个问题大家不必太过注意。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/585054.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-12
下一篇 2022-04-12

发表评论

登录后才能评论

评论列表(0条)

保存