1. 程式人生 > >陣列引數傳遞及程式設計技巧

陣列引數傳遞及程式設計技巧

在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不能超過實際大小,程式就能安全執行。

以上。