C之數組參數和指針參數(三十一)
那麽當初在設立 C 語言時,主要是用於 Unix 操作系統,而 Unix 效率要求很高。所以 C 語言以高效作為最初設計目標:a> 參數傳遞的時候如果拷貝整個數組執行效率將會大大下降;b> 參數位於棧上,太大的數組拷貝將導致棧溢出。函數調用棧是用一片內存來存放的,如果棧溢出,那麽函數調用將無法執行,程序將會崩了。
二維數組參數同樣也存在退化,它可以看做是一維數組,它中的每個元素是一維數組。二維數組參數中第一維的參數可以省略,如:void f(int a[5]) ==> void f(int a[]) ==> void f(int* a); void g(int a[3][3]) ==> void g(int [][3]) ==> void g(int (*a)[3])
數組參數 | 等效的指針參數 |
一維數組:float a[5] | 指針:float* a |
指針數組:int* a[5] | 指針的指針:int** a |
二維數組:char a[3][4] | 數組的指針:char(*a)[4] |
我們可以看出指針數組作為參數時才退化為二維指針。那麽在 C 語言中無法向一個函數傳遞任意多的多維數組,必須提供除第一維之外的所有維長度;其中第一維之外的維度信息用於完成指針運算,N維數組的本質是一維數組,元素是 N - 1 維的數組,對於多維數組的函數參數只有第一維是可變的。下來我麽以代碼為例進行分析,代碼如下
#include <stdio.h> void access(int a[][3], int row) { int col = sizeof(*a) / sizeof(int); int i = 0; int j = 0; printf("sizeof(a) = %d\n", sizeof(a)); printf("sizeof(*a) = %d\n", sizeof(*a)); for(i=0; i<row; i++) { for(j=0; j<col; j++) { printf("%d\n", a[i][j]); } } printf("\n"); } int main() { int a[3][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}}; int aa[2][2] = {0}; access(a, 3); access(aa, 2); return 0; }
我們看到在程序中我們在第25和26行分別定義了3*3,2*2的二維數組,但是 access 函數裏參數的數組參數第二維指定是3。所以我們在第29行調用這個函數會報錯,因為類型不匹配。我們來看看編譯結果
我們看到它報警告了,也就是說這個程序雖然通過編譯了,但是它允許的結果是不確定的。我們看到我們定義的 aa 數組是 2*2 的,但是它打印出了6個數,也就是當成 2*3 的了。所以我們這樣調用是不對的。
下來我們看個三維數組的代碼,代碼如下
#include <stdio.h> void access_ex(int b[][2][3], int n) { int i = 0; int j = 0; int k = 0; printf("sizeof(b) = %d\n", sizeof(b)); printf("sizeof(*b) = %d\n", sizeof(*b)); for(i=0; i<n; i++) { for(j=0; j<2; j++) { for(k=0; k<3; k++) { printf("%d\n", a[i][j][k]); } } } printf("\n"); } int main() { int aa[2][2] = {0}; int b[1][2][3] = {0}; access_ex(b, 1); access_ex(aa, 2); return 0; }
我們在 access_ex 函數裏指定的是第二維是2,第三維是3。但是我們定義的數組 aa 不是這樣的,我們看看編譯結果
我們看到第二個編譯出的結果也是不確定的。通過本節對數組參數和指針參數的學習,總結如下:1、C 語言中只會以值拷貝的方式傳遞參數,並且數組參數必然退化為指針;2、多維數組參數必須提供除第一維之外的所有維長度;3、對於多維數組的函數參數值第一維是可變的。
歡迎大家一起來學習 C 語言,可以加我QQ:243343083。
C之數組參數和指針參數(三十一)