[C/C++]细数二维数组的坑
二维数组作为函数参数
先上代码如下:
#include <stdio.h>
void disp(int a[][2]){printf("%d\n",a[0][0]);}
int main(){
int a[][2] = {1,2,3,4};
disp(a);
return 0;
}
这是naive的实现,假设disp函数的定义如下呢?
void disp(int *a[2]){printf("%d\n",a[0][0]);}
编译提醒(没有错误)如下:
main.c:6:8: warning: incompatible pointer types passing 'int [2][2]' to
parameter of type 'int **' [-Wincompatible-pointer-types]
disp(a);
main.c:3:17: note: passing argument to parameter 'a' here
void disp(int *a[2]){printf("%d\n",a[0][0]);}
^
1 warning generated.
从编译结果来看,只是产生了warning,没有error,但是运行的时候出现段错误!这也从一方面验证了对于代码的warning也要保持足够警惕。
在Ubuntu下的提示如下:
note: expected ‘int **’ but argument is of type ‘int (*)[2]’
究其原因是上述函数声明的是指向2个元素的一维数组,每个元素类型为指向int的指针类型。为什么会导致这样的理解?’[]’的优先级比’*‘高。修正如下:
void disp(int (*a)[2]){printf("%d\n",a[0][0]);}
此时声明了一个指针,指向具有2个元素的一维数组。2表示的是二维数组的列,这样就满足了expected int。
返回数组
先看代码:
#include <stdio.h>
int* func(int* a,int len){
//int* tmp = new int[len];
for(int i = 0;i < len;i++){a[i]++;}
return a;
}
int main(){
int len = 4;
int a[] = {1,2,3,4};
int *b = func(a,len);
for(int i = 0;i < len;i++){printf("%d ",b[i]);}
return 0;
}
假设代码中取消注释行,重写函数func有:
int* func(int* a,int len){
int tmp[len];
for(int i = 0;i < len;i++){tmp[i]=a[i];}
return tmp;
}
编译提示:
main.cpp:6:9: warning: address of stack memory associated with local variable
'tmp' returned [-Wreturn-stack-address]
return tmp;
^~~
1 warning generated.
很显然,从函数调用过程来说,当函数返回时,调用栈的空间全部释放。相比与原来的定义,是直接在传入的数组空间进行操作,所以直接返回即可。
解决的方法就比较清楚了,在局部函数内开辟在堆上的空间。
int* func(int* a,int len){
int* tmp = new int[len];
for(int i = 0;i < len;i++){tmp[i]=a[i];}
return tmp;
}
注意,在调用该函数后进行内存空间的释放。考虑到空间的开辟和释放不在同一个位置,很容易出现忘记释放内存的情况,因此另外一种情况是在main函数中开辟一个空间,将该空间作为函数参数传递到func中,赋值后返回,这种方式和原始定义类似。
总结:参数传递要指定列数,返回要手动开辟和释放内存空间。
重要参考: