C语言编程的过程中,不可避免的会碰到二维或二维以上的数组作为函数的形参的情况,在以前的编程过程中,习惯了动态数组的应用,很是使用直接定义高维数组。最近在编程的过程中就碰到了这个问题:有如下的测试程序:
voidtest(int **x,int Row,int Col);
voidtest(int **x)
{
for(int i=0;i<Row;i++)
for(int k=0;k<Col;k++)
x[i][k] += 100.0;
}
int main(int argc, char *argv[])
{
int x[3][3];
for(int i=0;i<3;i++)
for(int k=0;k<3;k++)
x[i][k] = i*k;
for(int i=0;i<3;i++)
for(int k=0;k<3;k++)
printf("x[%d][%d]= %e\n",i,k,x[i][k]);
getch();
return 0;
}
编译时提示Cannot convert 'int [*][3]' to int **'。
将调用方式强制进行类型转换:test((int **)x),编译通过,运行出错,提示非法越界。
因为栈上分配的数组和堆上分配的数组在内存排列上可能不相同,直接定义的数组是存储在程序的堆栈区,数据占用连续的区间;而动态申请的数组是在系统的远堆上(far heap),除最后一维的元素是连续存放的外,其他维上的元素有可能不是在一块连续的内存区域里。
//栈上:
int ia[2][2] = {2,3,4,5}; //4个元素是连续排列的内存段
//堆上:
int **p = new int*[2]; //只有每行内是连续排列,各行并不一定连续排列
for ( int i = 0; i < 2; i++ )
{
p[i] = new int[2];
}
for ( int i = 0; i < 2; i++ )
{
for ( int j = 0; j < 2; j++ )
{
p[i][j] = ia[i][j];
}
}
所以对栈上的数组用int **p指向首地址,因为int **p一次解引用为地址指针,而非堆上的指向数组的指针,所以二次解引用会出错。 如果找一个通用方程只能用:
void f( int *p, int row, int col ) //给出数组的行和列,对堆上的数组不合适
{
for ( int i = 0; i < row; i++)
{
for ( int j = 0; j < col; j++ )
{
cout < < p[i * row + j] < < " ";
}
cout < < endl;
}
}
int main(){
//.........
int ia[2][2] = {2,3,4,5};
f( (int*)ia, 2, 2 );
}
采用上面的通用办法还是比较麻烦,这无形中对编程增加了难度,为了避免这个麻烦可以采用动态数组的形式,将原来采用直接定义的数组全部换成动态数组,类似开头例子中被注释掉的那部分代码,当然这样也有后续的麻烦,动态数组的生命周期完成后必须释放内存空间,这也有点罗嗦,但是毕竟可以直接使用数组的形式,比上面的通用方式还是要简单一点。
如果执意要使用直接定义的数组该怎么办呢?
方法一:
voidtest(double x[][3], int Row,int Col);
调用方式 test(x,Row,Col);
对于多维数组作为参数,除第一维之外的其它维必须指定维数,否则是肯定编译不过去的。
从上面的对直接定义的数组的引用情况看,直接定义的数组的使用比较麻烦,一旦直接定义数组的维数发生变换,函数的定义必须相应的修改,否则程序就会出错,这也增加了程序进一步开发的麻烦,为了一劳永逸的解决这个问题,建议还是使用动态数组的方法,虽然需要手工释放内存,但是除却了后续的麻烦。