數組形參


      數組有兩個特殊的性質。一是不能復制數組;二是使用數組名字時,數組會自動轉化為指向其第一個元素的指針。由於數組不能復制,所以無法編寫使用數組類型形參的函數,因為數組會被自動轉化為指針。

   數組形參是個容易出問題的地方。因為對於C/C++新手而言,最大的驚訝是C++中根本不存在所謂的“數組形參”,因為數組在傳入時,實質上只傳入指向其首元素的指針

1 void average(int ary[12]); // 形參ary是一個int*
2
3 //...
4
5 int anArray[] = {1, 2, 3}; // 一個具有3個元素的數組
6
7 const int anArraySize = sizeof(anArray)/sizeof(anArray[0]); // == 3
8
9 average(anArray);//error

 

這種從數組到指針的自動轉換被賦予了一個迷人的技術術語:“退化”,即數組退化成指向其首元素的指針。順便提及,同樣的事情也發生在函數上。一個函數型參數會退化成一個指針。不過,和數組退化時丟失邊界不同,一個退化的函數具有良好的感知能力,可以保持其參數類型和返回類型。

 

    由於在數組形參中數組邊界被忽略了,因此通常在聲明時最好將其省略。然而,如果函數期望接受一個指向一個元素序列(換句話說,就是數組)的指針作為參數,而不是指向單個對象的指針,那么最好這樣聲明:
void average(int ary[]); // 形參ary仍然是一個int*
另一方面,如果數組邊界的精確數值非常重要,並且希望函數只接受含有特定數量元素的數組,可以考慮使用一個引用形參:
 
 void average(int (&ary)[12]);
// ...
int main()
{
int i=0,j[2]={0,1};
int k[12]={0,1,2,3,4,5,6,7,8,9,10,11};
average(&i); //error: 參數類型不是10個int型
average(j); //error:
average(k); //ok;
return -1;
}
現在,由於average需要接受的參數為12個元素的數組,而anArray是一個只含有3個元素的數組,因此:

average(anArray); // 錯誤!anArray是一個int [3] !
 
 
    模板有助於代碼的泛化:
    template<int n>
    void average(int (&ary)[n]); // 讓編譯器幫我們推導n的值!
 
    不過,更為傳統的做法是將數組的大小明確地傳入函數:
    void average(int ary[], int size);
 
    當然,我們可以將這兩種方式結合起來:
    template<int n>
    inline void average(int (&ary)[n])
    {
         average_n(ary, n);
    }
 
    從以上討論中我們應該清晰地獲知,使用數組合作函數參數最大的問題在於,數組的大小必須以形參的方式顯式地編碼,並以單獨的實參傳入,或者在數組內部以一個結束符值作為指示。另一個困難在於,不管數組是如何聲明的,一個數組通常是通過指向其首元素的指針進行操縱。如果那個指針作為實參傳遞給函數,我們前面聲明引用形參的技巧將無濟於事。
int *anArray2 = new int [anArraySize];
//...
average(anArray2); //錯誤,不可以使用int *初始化int (&)[n]
average_n(anArray, anArraySize); // 沒問題
 
    出於這些原因,經常采用某種標准窗器(通常是vector或string)來代替對數組的大多數傳統的用法,並且經常應該優先考慮使用標准容器。
    從本質上來說,多維數組形參並不比一維數組來得困難,但它們看上去更具挑戰性;
void process(int ary[10][20]);
    和一維數組一樣,形參不是一個數組,而是一個指向數組首元素的指針。不過,多維數組是數組的數組,因此形參是一個指向數組的指針:
void process(int (*ary)[20]); //一個指針,指向一個具有20個int元素的數組
 
    注意,第二個邊界沒有退化,否則將無法對形參執行指針算術。如前所述,讓代碼的讀者清晰地知道你期望的實參是一個數組,這通常是一個好主意:
void process(int ary[][20]); // 仍然是一個指針,但更清晰
 
    對多維數組形參的有效處理往往退化成一個低級的編程練習,此時需要程序員取代編譯器執行索引計算。
   

void process_2d(int *a, int n, int m)
{
      for (int i = 0; j < n; ++i)
            for (int j = 0; j < m; ++j)
                  a[i*m+j] = 0;
}

    同樣,有時模板有助於讓事情更干凈利落:

 

template<int n, int m>
inline void process(int (&ary)[n][m])
{
      process_2d(&ary[0][0], n, m);
}

 

    一句話數組形參是個討厭的家伙,和它親近你得小心。





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM