C++二维数组作参数时和二维指针的异同

二维数组传参
二维数组不同于一位数组,一维数组传参数时只需要传指针即可,无需指定大小。二维做参数时必须指定第二维的大小,否则编译不过。

void lalala(int a[][],int m, int n) //编译报错
void lalala(int a[][10],int m, int n) //编译通过
 

因为对于表达式a[i][j]来说,编译器认为它的含义是((a+i)+j)。

而C++中的二维数组的实质是一维数组实现的,对于数组array[m][n]来说,(array+i)实质上是(array + i * n),也就是说a[i][j]的地址是(a+in+j)如果不指定第二维的大小,编译器便无法识别(a+i)的运算方式,就无法寻址。

如果用二维指针作参数
void lalala(int **a,int m, int n) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
a[i][j] = i * j;
cout << &a[i][j] - *a << " ";
}
cout << "\n";
}
}
这样是能够编译通过的,但是当调用函数时,我们需要对数组进行强制类型转换(必须转换为int **,因为int *与int[10]类型不同)。

int m = 10;
int n = 10;
int array[10][10];
lalala((int **)array,m,n);
你一定觉得会运行得很完美,但事实上这样虽然能编译通过,但在运行得时候会出错。

0xC0000005: 写入位置 0xCCCCCCCC 时发生访问冲突!

原因仍然是,当二维数组经过强制类型转换后,array[i][j] 中的 *(array+i) 不知道如何计算,最后无法寻址。

显然,一定要指定二维数组的第二维大小十分苛求,这样的函数我们肯定不能容忍,那有什么解决办法呢?

解决方法
使用一维指针做参数
void lalala(int a,int m, int n) { for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { a[in+j] = i * j;
cout << &a[i*n+j] - a << " ";
}
cout << "\n";
}
}
int main() {
int m = 10;
int n = 10;
int array[10][10];
lalala((int *)array,m,n);
}
我们知道,二维数组本质是一维数组实现的,其后申请的内存空间是连续的,所以可以将二维数组强制转换成一维指针,然后手动计算地址 (a + in+j) 来解决问题,因为 a[in+j] 和 (a + in+j) 在语义上实际是一样的。

使用二维指针做参数
如果非要二维指针做参数,则有两种做法。

  1. 在函数实现中手动寻址
    利用a[i][j]的语义,在函数实现中将a[i][j]手动转换成 ((int)a + i * n + j),注意要先将二维指针*a强制转换成(int)a,如果只使用*a的话,在某些编译器下,仍然会出现前面的运行时寻址错误,内存无法读取。

void printValue(int **a,int m, int n) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
*((int*)a + i * n + j) = i * j;
cout << ((int)a + i * n + j) << " ";
}
cout << "\n";
}
}
int m = 10;
int n = 10;
int array[10][10];
printValue((int **)array,m,n);

2.用二维指针动态生成二维数组
我们在函数里参数写int **a,在函数实现中依旧使用表达式a[i][j]。

void printAddress(int **a,int m, int n) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
a[i][j] = i * j;
cout << &a[i][j] - *a<< " ";
}
cout << "\n";
}
}
2.1 一种动态生成方式(二维数组行与行之间在内存上不连续)
int m = 10;
int n = 10;
int **array = new int *[m]; //动态生成一组一维指针
for (int i = 0; i < m; i++) {
array[i] = new int[n]; //每组行指针申请一段内存
}
printAddress(array, m, n);

这样的确能够解决问题。但是

我们看到生成的二维数组地址并不一定连续,array[i][j]的实际寻址方式是 ((a+i)+j) 。

并不是我们C++自带的二维数组那样((int)array + i * n + j) 。

也就是说,我们这样动态生成的二维数组,遇到解决方法1中的printValue那样的函数内部实现的手动寻址方式就要gg啦。

2.2 更好的生成方式(二维数组在内存上完全连续)
int m = 10;
int n = 10;
int **array = new int *[m]; //动态生成一组一维指针
array[0] = new int[m*n]; //申请一段连续的二维数组内存
for (int i = 1; i < m; i++) {
array[i] = array[i - 1] + n; //确定每一段数组之间的间隔
}
printAddress(array, m, n);

可以看出,这样动态生成的二维数组,在构造上与C++自带的二维数组完全一致,可以看做由一个一维数组改造而来。只不过,它显式地规定了每一行的行指针(在C++原生的二维数组中并没有这些指针),这样array[i][j] 中(*array + i)部分的计算就不存在任何问题了。

这样就可以在不管函数怎么实现的情况下,对二维数组以二维指针的形式进行动态传参。

本文转载自: https://blog.csdn.net/fairyloycine/article/details/82917785

相关推荐

发表评论

电子邮件地址不会被公开。 必填项已用*标注

微信扫一扫

微信扫一扫

微信扫一扫,分享到朋友圈

C++二维数组作参数时和二维指针的异同
返回顶部

显示

忘记密码?

显示

显示

获取验证码

Close