在说二维数组前先回顾一下一维数组的参数传递,对二维数组的解引用、指针数组、数组指针不是很了解的能够先看一下这篇随笔:二维数组(解引用、指针数组、数组的指针)html
一维数组做为实参传入函数时,接收的形参有两种形式程序员
第一种形式:express
1 #include <stdio.h>
2
3 void fun(char s[]); 4 int main() 5 { 6 char num[10] = "Hello"; 7 fun(num); 8
9 return 0; 10 } 11
12 void fun(char s[]) 13 { 14 puts(s); 15 }
第二种形式:数组
1 #include <stdio.h>
2
3 void fun(char s[]); 4 int main() 5 { 6 char num[10] = "Hello"; 7 fun(num); 8
9 return 0; 10 } 11
12 void fun(char *s) 13 { 14 puts(s); 15 }
下面分析下第一种,由于当数组做为实参进行传递时会自动退化为指针(是一种隐式转换),因此传入的是一维数组num的首地址,即&num[0],做为接收的形参char s[]也会自动退化为char *类型的指针,因此数组在进行传递时函数
传递的是数组的地址而不是数组的元素,由于一维数组的形参是会自动退化为指针的,因此数组长度填不填都无所谓,形参数组的长度是大于实参的长度仍是小于实参的长度都没有影响(既然的都退化了,指针又没有像数组长度这个概念因此填不填长度都无所谓了)post
那么为何C语言不容许直接传递数组的全部元素呢?url
数组是一系列数据的集合,数据的数量没有限制,可能不多,也可能出乎意料的大,对它们进行内存拷贝有多是一个漫长的过程,会严重拖慢程序的效率,为了防止技艺不佳的程序员写出低效的代码,C语言没有从语法上支持数据集合的直接赋值。spa
先上代码:3d
1 #include <stdio.h>
2
3 int main() 4 { 5 double num[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 6 char **p; 7
8 printf("%d\n", sizeof(num)); 9 printf("%d\n", sizeof(num+0)); 10 printf("%d\n", sizeof(*num)); 11 printf("%d\n", sizeof(&num)); 12 printf("%d\n", sizeof(p)); 13
14 return 0; 15 }
读者能够先想一下结果应该是什么,再往下看指针
运行结果以下:
第一个sizeof(num),大部分人应该都知道,应该是数组num的长度*类型所占字节数,结果为80(说明在使用sizeof时数组没有退化,也间接说明了sizeof不是函数而是关键字)
第二个sizeof(num+0),这个就带有必定的迷惑性了,num+0包含了一层隐式转化,转换后变成了char *类型,结果为4
第三个sizeof(*num),这比较好理解,就是sizeof(num[0]),结果为8
第四个sizeof(&num),num自己就是数组的首地址,也就是&num[0],再前面再加一个取地址符,也就是地址的地址,结果为4,注意&num的类型为double (*p)[10],若是要存储&num的值,
须要用double (*)[10]类型的变量(通常不这么用,没什么意义至于为何没意义下面会细说)
关于这种数组地址的地址,下面上代码实测一下
1 #include <stdio.h>
2
3 int main() 4 { 5 double num[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 6 printf("%p\n%p", num, &num); 7
8 return 0; 9 }
运行结果为:
从运行结果能够看出,数组首地址的地址的值与数组首地址的值是如出一辙的,这也就是为何上面说没什么意义的缘由
第五个sizeof(p),p是一个二级指针,和一级指针相同,都是占4个字节,结果为4,(读者能够尝试下不管多少级指针,只要编译器的环境是32位的占的字节数都是4)
二维数组做为实参传入函数时,接收的形参形式有以下几种
第一种:
1 #include <stdio.h>
2
3 void fun(char p[][6]); 4
5 int main() 6 { 7 char ss[2][6] = {"hello", "hi"}; 8
9 fun(ss); 10 return 0; 11 } 12
13 void fun(char p[][6]) 14 { 15 puts(p[0]); 16 puts(p[1]); 17 }
第二种:
1 #include <stdio.h>
2
3 void fun(char p[][6]); 4
5 int main() 6 { 7 char ss[2][6] = {"hello", "hi"}; 8
9 fun(ss); 10 return 0; 11 } 12
13 void fun(char (*p)[6]) 14 { 15 puts(p[0]); 16 puts(p[1]); 17 }
二维数组在做为实参进行传递时也是会退化的,二维数组ss[2][6]会退化成ss(*)[6]类型数组的指针,一样若是形参也写成二维数组的形式,就像第一种那样char p[][6](注意第二维不能省略,不能省略是由于内存的寻址方式的特色所决定的),也会自动隐式转化成char (*p)[6]这样的形式
在C99中对指针的退化进行了说明:
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type
“array of type” is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.
上面这句话说的意思是, 数组在除了3种状况外, 其余时候都要"退化"成指向首元素的指针.
好比对 char s[10] = "Hello";
这3中例外状况是:
(1) sizeof(s)
(2) &s;
(3) 用来初始化s的"Hello";
(tips:数组的首地址是常量,不可更改,指针保存的地址是变量,能够更改)