陣列引數傳遞及程式設計技巧
在C++中傳遞陣列引數是一件很簡單的事情,但是這裡面也有一些需要注意的細節,不能忽視,(只能說C++太難了,也太好玩了)。
陣列形參
在這個裡面,陣列是作為形參傳遞的,有以下幾種:
void printArr(int*) {/* ... */}
void printArr(int []) {/* ... */}
void printArr(int [10]) {/* ... */}
這三種達到的目的是一樣的,也是等價的,都會被看做int *
形參的長度會引起誤解
編譯器會忽略任何陣列形參指定的長度的,根據陣列的長度(權且這樣說),可以在函式內部遍歷陣列:
void printArr(const int a[10]){
for(size_t i = 0; i != 10; i++){
cout<< a[i] <<endl;
}
}
這裡我們已經知道,編譯器會忽略陣列的長度,但是我們在形參寫了長度,這樣我們就預設使用了這個長度(會出現一些不可控的問題)。
例如,如下的呼叫都是合法的:
int main(){
int i =0, j[2] = {0,1};
printArr(&i); //ok! &i 是 int *, 但是執行會出現越界。
printArr(j); // ok! j 會被轉換為 int *, 但是也會越界。
return 0;
}
這裡雖然編譯沒問題,但是呼叫和執行都是有問題的。
陣列實參
和其他型別一樣,C++比C多了引用型別,(這裡強調一下,標準C99版本的C語言是沒有引數引用的)。陣列形參可以定義為引用或非引用型別。大部分情況如下,陣列以普通的非引用型別用作型別傳遞,此時陣列會悄悄的轉換為指標,一般來說,非引用型別的形參會初始化為其相應的實參副本,而在傳遞陣列時,實參是指向陣列的第一個元素的指標,形參是複製了指標的值,改變的是指標指向的值,並沒有更改指標本身的值。
通過引用來傳遞陣列
陣列形參可以宣告為陣列的引用,如果形參是陣列的引用,編譯器不會把陣列實參轉化為指標,而是傳遞陣列本身,這種情況下,陣列大小成為形參和實參型別的一部分,編譯器會檢查陣列的大小。
void printArr(int (&a)[10]) { /* ... */ }
int main(){
int i = 0, j[2] = {0,1}, k[10] = {0};
printArr(&i); // error!
printArr(j); //error!
printArr(k); // ok!
return 0;
}
這個版本,會嚴格檢查陣列的大小。
多維陣列的傳遞
在C++中本來沒有多維陣列,所以其實多維陣列,就是陣列中的陣列。
這裡區分下陣列指標和指標陣列的問題:
1. 陣列指標,是指標。 int (*a)[10];
2. 指標陣列,是陣列。 int *a [10];
詳情看我的部落格:C++學習 - 陣列指標/指標陣列.
除了第一維以外的所有維的長度都是元素型別的一部分,必須明確指定。
上面這句話很重要,它說明了傳遞多維陣列引數必須的形式。
例子:
void printArr( int (*a)[10], int rowSize );
上面這個語句,括號是省不了的,一定要加上。假如不加的話。
void printArr( int a[][10], int rowSize );
一定要這樣寫才行。
傳遞給函式的陣列處理
非引用的陣列形參,只是檢查型別,確保實參是和陣列元素具有同樣型別的指標,而不會檢查實際上是否指向陣列指定大小。
有三種常見的辦法來保證函式的操作,不會讓資料實參越界操作。
標記結束
第一種是在陣列本身防止一個標記來檢測陣列的結束,C風格的字串是以null為結束標記的。
標準庫方法
第二種是傳遞指向陣列第一個和最後一個元素的下一個位置的指標,這種變成風格是由標準庫所使用的技術。例如:
void printArr(const int *beg, const int *end){
while(beg != end){
cout << *beg++ <<endl;
}
}
int main(){
int j[2] = {0,1};
printArr(j, j+2);
return 0;
}
這種迴圈很像用vector
迭代器編寫的程式。
顯示傳遞陣列大小
第三種方法就是把第二個方法中的結尾指標,變成陣列的大小,這種方法在C程式和標準化之前的C++程式是十分普遍的。
void printArr(const int a[], size_t size){
for(size_t i = 0; i != size; ++i){
cout << a[i] << endl;
}
}
int main(){
int j[] = {0,1};
printArr(j, sizeof(j)/sizeof(*j));
return 0;
}
這個版本是用來形參size來確定要輸出的元素個數,這樣size可以控制訪問陣列的範圍,size不能超過實際大小,程式就能安全執行。
以上。