在說二維數組前先回顧一下一維數組的參數傳遞,對二維數組的解引用、指針數組、數組指針不是很瞭解的能夠先看一下這篇隨筆:二維數組(解引用、指針數組、數組的指針)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:數組的首地址是常量,不可更改,指針保存的地址是變量,能夠更改)