如何將二維數組作為函數的參數傳遞
今天寫程序的時候要用到二維數組作參數傳給一個函數,我發現將二維數組作參數進行傳遞還不是想象得那么簡單里,但是最后我也解決了遇到的問題,所以這篇文章主要介紹如何處理二維數組當作參數傳遞的情況,希望大家不至於再在這上面浪費時間。
正文:
首先,我引用了譚浩強先生編著的《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 p[m][n];
如果要取p[i][j]的值(i>=0 && i<m && 0<=j && j < n),編譯器是這樣尋址的,它的地址為:
p + i*n + j;
從以上可以看出,如果我們省略了第二維或者更高維的大小,編譯器將不知道如何正確的尋址。但是我們在編寫程序的時候卻需要用到各個維數都不固定的二維數組作為參數,這就難辦了,編譯器不能識別阿,怎么辦呢?不要着急,編譯器雖然不能識別,但是我們完全可以不把它當作一個二維數組,而是把它當作一個普通的指針,再另外加上兩個參數指明各個維數,然后我們為二維數組手工尋址,這樣就達到了將二維數組作為函數的參數傳遞的目的,根據這個思想,我們可以把維數固定的參數變為維數隨即的參數,例如:
void Func(int array[3][10]);
void Func(int array[][10]);
變為:
void Func(int **array, int m, int n);
在轉變后的函數中,array[i][j]這樣的式子是不對的(不信,大家可以試一下),因為編譯器不能正確的為它尋址,所以我們需要模仿編譯器的行為把array[i][j]這樣的式子手工轉變為:
*((int*)array + n*i + j);
在調用這樣的函數的時候,需要注意一下,如下面的例子:
int a[3][3] =
{
{1, 1, 1},
{2, 2, 2},
{3, 3, 3}
};
Func(a, 3, 3);
根據不同編譯器不同的設置,可能出現warning 或者error,可以進行強制轉換如下調用:
Func((int**)a, 3, 3);
對二維數組的理解,可以從下面幾種表示方法進行:
1. a[0],a[1],...,a[N] 表示的是二維數組每一行的首地址;
2. a 指向一維數組{a[0],a[1],a[2],...}的首地址;
3. a[1]+2 表示指向二維數組第二行第三列的首地址;
4. *a[0],*a[i],...,表示指向第 i 行的二維數組的首地址的元素值(等同於a[0][0],a[i][0])
5. 比較難理解,但是比較重要的一點:我們知道,一維數組中*(a+i) = a[i] ,此假設對二維數組也是無條件等價的。
1 #include <iostream> 2 using namespace std; 3 4 5 void func1(int *array,const int m,const int n) 6 { 7 const int M = m; 8 int arrayList[10][10] = {0}; 9 for (int i =0;i<M;i++) 10 { 11 for (int j = 0;j<M;j++) 12 { 13 arrayList[i][j] = *(array+n*i+j); 14 cout<<' '<<arrayList[i][j]; 15 } 16 cout<<endl; 17 } 18 19 20 } 21 void main() 22 { 23 24 int a[5][5] = {{1,2,3,4,5},{1,3,4,5,6},{3,4,5,6,7},{1,4,6,7,8},{3,4,5,6,7}}; 25 int b[3]={4,2,7}; 26 cout<<a<<endl; 27 cout<<a[0]<<endl; 28 cout<<&a[0]<<endl; 29 cout<<*a<<endl; 30 cout<<*a[2]<<endl; 31 func1((int*)a,5,5); 32 cout<<b<<endl; 33 cout<<*b<<endl; 34 35 }
