[精彩]二维数组传参传值
二维数组传参||传值
先给出问题:
像下面这样的数组,在函数中如何传参,也就是说如何保证虚参与实参类型一致。
char str_arr[3][10] = {"yes","no","uncertain"}; char *str_array[] = {"yes","no","unsure"};
函数原型:
void func1( char (*a)[10] )
void func2( char **a )
调用:
func1( str_arr );
func2( str_array); 如果向func2()中传入str_arr会怎么样呢,编译器会警告:传递参数 1 (属于 ‘func2’)时在不兼容的指针类型间转换。即虚参与实参类型不一致。
同理,也不能向func1()中传入str_array。
我们给出完整的测试程序:
/********二维数组传参测试程序***************/
#include
void func1( char (*a)[10])
{
int i;
for(i=0;i<3;i++)
printf("%s/n",a[i]); }
void func2( char **a )
{
int i;
for(i=0;i<3;i++)
printf("%s/n",*(a+i)); }
int main()
{
char str_arr[3][10] = {"yes","no","uncertain"};
char *str_array[] = {"yes","no","unsure"};
char *str[3] = {"a","b","c"};/*这两种表达效果一样*/
func1(str_arr);
func2(str_array);
return 0;
}
/******************end*******************/ 运行结果:
[root@localhost ansi_c]# gcc test.c [root@localhost ansi_c]# ./a.out yes
no
uncertain
yes
no
unsure
[root@localhost ansi_c]#
如果将
func1(str_arr);
func2(str_array);
改成:
func1(str_array);
func2(str_arr);
会怎么呢,
[root@localhost ansi_c]# gcc test.c test.c: 在函数 ‘main’ 中:
test.c:22: 警告:传递参数 1 (属于 ‘func1’)时在不兼容的指针类型间转换 test.c:23: 警告:传递参数 1 (属于 ‘func2’)时在不兼容的指针类型间转换
这两种数组的正确赋值应该如下:
char str_arr[3][10] = {"yes","no","uncertain"};
char *str_array[] = {"yes","no","unsure"};
char (*pa)[10] = str_arr;
char **p = str_array; pa和p才是和他们相一致的类型。
当然,如果不是传参的话,在main()函数中就不会发生这么多烦恼了。 /*************非传参时的情况************************/ #include
int main()
{
char str_arr[3][10] = {"yes","no","uncertain"};
char *str_array[] = {"yes","no","unsure"};
char *str[3] = {"a","b","c"};
int i;
for(i=0;i<3;i++)
printf("%s/n",str_arr[i]);
for(i=0;i<3;i++)
printf("%s/n",str_array[i]);
return 0;
}
/*************************************/ 运行结果:
[root@localhost ansi_c]# gcc test1.c [root@localhost ansi_c]# ./a.out
yes
no
uncertain
yes
no
unsure
[root@localhost ansi_c]#
这说明了一点,在没传参之前,main()函数清楚它们都是二维数组。对于上面给出的两种函数原型: 函数原型:
void func1( char (*a)[10] )
void func2( char **a ) 这两种传参方法有什么不同呢,这们对实参有什么要求呢,
上面只是抛出了一个问题,我在这里的主题是想搞清楚二维数组传参有什么奥秘,而非只针对这一个问题提出解决方法。
后面从基础的开始讨论。
我们先看看教材上怎么讲这一块的,
谭浩强的《C程序设计》二维数组作为参数传递,原文如下(略有改变,请原谅):
[原文开始]
可以用二维数组名作为实参或者形参,在被调用函数中对形参数组定义时可以可以指定所有维数的大小,也可以省略第一维的大小说明,如:
void Func(int array[3][10]);
void Func(int array[][10]);
二者都是合法而且等价,但是不能把第二维或者更高维的大小省略,如下面的定义是不合法的:
void Func(int array[][]);
因为从实参传递来的是数组的起始地址,在内存中按数组排列规则存放(按行存放),而并不区分行和列,如果在形参中不说明列数,则系统无法决定应为多少行多少列,不能只指定一维而不指定第二维,下面写法是错误的:
void Func(int array[3][]);
实参数组维数可以大于形参数组,例如实参数组定义为:
void Func(int array[3][10]);
而形参数组定义为:
int array[5][10];
这时形参数组只取实参数组的一部分,其余部分不起作用。 [原文结束]
也就是说多维数组传参要指定第二维或者更高维的大小,可以省略第一维的大小。 像 int array[3][4],要传参的话,函数原型可以为下面三种的任一种:
void func(int a[3][4])
void func(int a[][4])
void func(int (*a)[4])
调用时为:func(array);
同时教材里也说了,如果在型参里不说明列数,则编译器无法决定应为多少行多少列。那么能不能把
int array[3][4]的数组名 array 传给 void func(int **a)呢,
看下面:
/**********************************/ #include
int main()
{
int array[3][4];
int **p = array;
}
**********************************/ root@localhost ansi_c]# gcc test2.c test2.c: 在函数 ‘main’ 中:
test2.c:5: 警告:从不兼容的指针类型初始化
[root@localhost ansi_c]#
虽然从本质上讲int array[3][4] 的数组名相当于二级指针,但它不等同于一般的二级指针,因为它还含有数组相关的信息,所以在main函数中:
char str_arr[3][10] = {"yes","no","uncertain"};
for(i=0;i<3;i++)
printf( "%s/n",str_arr+i );
它可以通过下标,每次跳过10个字节来寻址。我们再看看编译器是怎样处理数组的: 对于数组 int p[m][n];
如果要取p[i][j]的值(i>=0 && i
void fun( int *a, int m, int n) {
int i,j;
for( i=0; i
void f( char **a, int n)
{
int i;
printf("%c/n",*( (char*)a+0 ) );
printf("%c/n",((char * )a)[n] );
puts("------------OK");
for(i=0;i<3;i++)
printf("%s/n",(char*)a+i*n );
}
int main()
{
char str_arr[3][10] = {"yes","no","uncertain"};
f( (char **)str_arr, 10);
return 0;
}
/****************end*************************/
运行结果:
[root@localhost ansi_c]# ./a.out y
n
------------OK
yes
no
uncertain
[root@localhost ansi_c]#
这里也做了强制类型转换,转换成字符指针,
printf("%s/n",(char*)a+i*n ); 每个字符串的地址就是数组中字符'y'、'n'、'u'的地址, printf("%c/n",*( (char*)a+0 ) );字符在数组中的排列是顺序的,可以用 *( (char*)a+i )或 ((char * )a)[i]
表示。
当然这个程序也可以改成这样,完全不用二级指针:
/*****************************************************************/
#include
void f( char *a, int n)
{
int i;
printf("%c/n",*( a+0 ) );
printf("%c/n",(a)[n] );
puts("------------OK");
for(i=0;i<3;i++)
printf("%s/n",a+i*n );
}
int main()
{
char str_arr[3][10] = {"yes","no","uncertain"};
f( (char *)str_arr, 10);
return 0;
}
/*****************************************************************/
归根结底,还是把它转成一级指针来用。
下面做个小结:
数组传参
数组:
int array[4][10];
函数原型:
void func1( int a[][10] );
void func2( int (*a)[10] );
void func3( int *p, int col, int row );
函数调用:
func1( array );
func2( array );
func3( (int *)array, 4, 10 );
容易出错的地方:
int arr[][10];
int **p = arr;
这种方式是错误的.
应该是
int (*p)[10] = arr;
同理,也不能将arr传给fun( int **p) 另外数组传参之后会降级为指针,如:
#include
void Test(char a[][2])
{
int size = sizeof( a );//4 }
int main(void)
{
char a[3][2] = {'a','b','c','d','e','f'};
int size =sizeof( a );//6
Test( a );
return 0;
}
来源:
函数原型:要求传入一个动态二维数组
void func1(int **p,int row, int column)
{
}
调用:
int main()
{
int m,n;
int **b;
cin >> m;
cin >> n;
b = new int *[m];
for(int i=0; i