C++中二維數組做爲函數參數

在平時,咱們常常會遇到將整個數組做爲函數參數的狀況,一維數組的狀況,就是用數組名當形參和實參,傳遞的是數組的首地址。二維數組咱們用的也不少,可是老是有各類問題,今天我總結一下數組

有個很重要的一點,字符串「China」在編譯器眼裏就是一個地址!操做字符串是經過它在內存中的存儲單元的首地址進行的,這是字符串的終極本質函數

若是 "China", 存儲在內存中的 0x3000 0x3001 0x3002 0x3003 0x3004 0x3005 .spa

          s = "China" ,賦值了什麼,地址。指針

          其實真正的意義是 s ="China" = 0x3000;code

首先咱們從指針的角度從新認識下二維數組,int a[3][4],這裏的a是一個行指針,指向的是二維數組的行首,a+1指向的是第二行,指的是a[1],它的類型是int(*)[4]。a[i]是一個元素指針,好比a[0]是第1行的一維數組的數組名,指向的是a[0][0],a[0]+1指向的是a[0][1]。它的類型是int*。blog

int (*p)[4],這個時候p和a是等價的,由於都是行指針,類型都是int(*)[4]。內存

(1)二維數組指定行數列數做爲形參,實參是二維數組名字符串

void f(int a[3][4]); void f(int a[][4]); void f(int (*a)[4]);

上述三種都是等價的。可是不能省略數組的列數,由於實參傳遞的是二維數組的起始地址,主要緣由是二維數組在棧內分配的內存是連續的,它的每一行都有相同的元素,這樣,a[i][j] 和 *(*(a +i) +j)是同樣的,程序是知道array+i的i實際上偏移了i*N個單位,這也致使了在二維數組array[3][3]中,使用下標array[2][1]和array[1][4]是訪問的同一個元素,儘管後者的下標對於一個3*3矩陣來講是非法的,但這並不影響訪問。省略了列數,內存不知道如何存放二維數組了。編譯器

缺點:該方式的缺點是,必須事先固定數組的行數列數,不太方便。若是個人數組事先不知道多大,這種方法就不適合了。it

(2)二維數組當作一維數組訪問,實參的形式有兩種,但都是int* 型,一種是*a,一種是a[0],都指向的是一維數組的第一個元素

int a[2][2] = {2,3,4,5}; //4個元素時連續排列的內存段 //void f(int p[][2], int row, int col )//這種方式必須事先知道除第一維之外的維度的大小,不靈活
void f(int *p , int row, int col )//轉化爲一維數組來訪問
{ for(int i = 0; i < row; i++) { for(int j =0 ;j < col; j++) { cout<<p[i*col+j]<<" "; } } cout<<endl; }

在被調函數中,尋址的方式能夠是程序中的方式,也能夠是*(p+i*col+j)的方式。

這裏int** p =a;是錯誤的,由於p是int** 型,而a是int(*)[2]的。

解釋下緣由:(1)類型不一樣是很明顯的(2)從指向的角度來講,a表示的是數組中a[0]的地址,也就至關於a[0][0]的地址,若是p=a的話,p也表明a[0][0]的地址,*p表明的是a[0][0]自己的值,**p訪問的是地址爲a[0][0](這裏等於2)的內存空間,這是不容許的。

可是有一種狀況就能夠這麼賦值

char *a[2]={"hello","world"}; char** p=a;

這些定義中a的類型不是int(*)[2],而是int* 了(按上述說應該是char*),p=a的話,*p=a[0],因此a表明的數組首地址,即a[0]的地址。*p也就是a[0]中存放的是"hello"的首地址,**p也就表示的是'h'了。這是合法的。

(3)二維數組經過二級指針傳遞,實參必須爲指針

void subfun(int n, char **subargs) { int i; for (i = 0; i < n; i++) { printf("subargs[%d] = %s\n", i, subargs[i]); } } void main() { char *a[3]; char args[][5] = {"abc", "def", "ghi"}; a[0] = args[0];  //equals with a[0] = &args[0][0]; 
    a[1] = args[1]; a[2] = args[2]; subfun(3, a);  //若此處爲subfun(3, args);則會編譯出錯 
}
void print(float **tab,int rows,int cols) { for(int i=0;i<rows;i++){ for(int j=0;j<cols;j++){ cout<<tab[i][j]<<" "; } cout<<endl; } } int main() { float ta[2][3]={{1.0,2.0,3.0},{4.0,5.0,6.0}}; float **p=new float *[2];//開闢行空間
    for(int i=0;i<3;i++) p[i]=new float[i];//開闢列空間
    for(int i=0;i<2;i++){    //賦值
        for(int j=0;j<3;j++){ p[i][j]=ta[i][j]; } } cout<<"ta: "<<endl; print(p,2,3);//打印 //p的內存釋放方式
    for(int i=0;i<3;i++) delete[]p[i]; delete []p; return 0; }

其實上述兩個程序是相同的處理方式,都是又額外申請了一段二級指針指向的內存,而後把數組值拷貝到這一塊內存中,用完後必須手動釋放內存。這樣就能夠和被調函數的二級指針對應上了。

另外還有一種強制轉換的傳參方式。

實參傳遞:

int a[3][4]; f((int **)a,3,4);

這樣在被調用數組中對對元素a[i][j]的訪問可使用以下形式:

*((int *)a+n*i+j); 

注意不能使用a[i][j]來直接訪問,由於編譯器沒法爲其定位。

這裏會有尋址方式的改變,好比何時下標尋址,何時只能指針尋址,暫時我沒有找到權威的解答,先不說了。之後補充。

相關文章
相關標籤/搜索