二维数组动态申请空间以及二维数组函数传参问题

最近在百度知道看到很多提问是关于RT的一些提问,下面是我在学习的过程中的一些总结,当然大虾可以忽视的,只是给初学者一些参考。

一 二维数组动态申请空间

假设我们要申请一个m行n列的整形数组,m、n的值可以在程序中动态改变

       1 使用malloc和free:

int **buf;

//申请

buf =(int **)malloc(sizeof(int *)*m);
for(int i=0;i<m;i++)
  buf[i]=(int *)malloc(sizeof(int)*n);

//释放

for(int i=0;i<m;i++)

  free(buf[i]);

free(buf);

       2 使用new和delete:

int **buf;

//申请

buf=new int*[m];

for(int i=0;i<m;i++) 

  buf[i]=new int[n];

//释放

for(int i=0;i<m;i++)

  delete [](buf[i]);

delete []buf;

二 二维数组函数传参

主要有以下三种方法,且以三种方法都是把数组地址作为参数传入

1    void foo(int a[][4]); //4可以为任一整型常数或者整形常量,不能为变量

函数foo必须传入一个列数为4的整形二维数组作为实际参数,行数可以任意,如:

int a[5][4];

foo(a);

但是不能传入一个二维指针,即使该指针已经申请了空间的列数为4,如以下做法是错误的

int **a;

申请5行4列的空间

foo(a);

2   void foo(int a[3][4]);  //3、4可以为任一整型常数或者整形常量,不能为变量

此方法等价与方法1,形参中第一维大小实际上不起任何作用

3   void foo(int **a);或者增加两个参数:实际数组的行数m和列数n void foo(int **a,int m,int n);

函数foo必须传入int** 类型的实际参数,且传参之前要动态申请空间,如:

int **a;    (例1)

申请5行4列的空间

foo(a);

但是不能传入一个静态定义的二维数组的地址,以下做法是错误的

int a[5][4];

foo(a);

把a进行强制类型转化不行吗,比如foo( (int **)a ), 我的回答是可以,但是需要注意一个非常重要的问题:

假设foo定义为 void foo(int **a){ int i=1,j=1;  a[i][j]=2 }

实际调用如下:
int a[5][4];  (例2)

foo( (int **)a );

此时编译可以通过,但是程序运行会出现错误,因为此时编译器计算a[i][j]时寻址发生错误

对一个m行n列的二维数组a,计算a[i][j]时,编译器如下寻址*((int*)a + n*i + j); 例2中a[5][4]强制转化为int ** 后,编译器不知道数组的列数n,因此无法寻址。但为什么例1中动态申请空间时却可以正确寻址,这是因为申请空间时,编译器就记下了二维地址a的行数和列数。

所以要想像例2那样调用,foo函数中就不能出项类似于a[i][j]的表达式,我们要自己手动寻址,并且至少要有数组的列数作为参数,如下

foo定义为 void foo(int **a,int m,int n){ int i=1,j=1;  *((int*)a + n*i + j)=2 }

int a[5][4]; 

foo( (int **)a );

这样就没有错误了

原文地址:https://www.cnblogs.com/TenosDoIt/p/3022106.html