函數>陣列作為函數參數


陣列作為函數參數

陣列可以作為函數的參數使用,進行資料傳送。陣列用作函數參數有兩種形式,一種是把陣列元素(下標變數)作為傳入參數使用;另一種是把陣列名作為函數的參數和傳入參數使用。

1.陣列元素作函數傳入參數

陣列元素就是下標變數,它與普通變數並無區別。 因此它作為函數傳入參數使用與普通變數是完全相同的,在發生函數使用時,把作為傳入參數的陣列元素的值傳送給參數,實現單向的值傳送。例5.4說明了這種情況。

【例8.7】判別一個整數陣列中各元素的值,若大於0 則輸出該值,若小於等於0則輸出0值。編程如下:

void nzp(int v)

{

    if(v>0)

      printf("%d ",v);

    else

      printf("%d ",0);

}

main()

{

    int a[5],i;

    printf("input 5 numbers\n");

    for(i=0;i<5;i++)

      {scanf("%d",&a[i]);

        nzp(a[i]);}

}

 

    本程式中首先定義一個無返回值函數nzp,並說明其參數v為整型變數。在函數體中根據v值輸出相應的結果。在main函數中用一個for語句輸入陣列各元素,每輸入一個就以該元素作傳入參數使用一次nzp函數,即把a[i]的值傳送給參數v,供nzp函數使用。

2.陣列名作為函數參數

用陣列名稱作函數參數與用陣列元素作參數有幾點不同:

1)用陣列元素作參數時,只要陣列類型和函數的傳入變數的類型一致,那麼作為下標變數的陣列元素的類型也和函數參數變數的類型是一致的。因此,並不要求函數的參數也是下標變數。換句話說,對陣列元素的處理是按普通變數對待的。用陣列名稱作函數參數時,則要求參數和相對應的傳入參數都必須是類型相同的陣列,都必須有明確的陣列說明。當參數和傳入參數二者不一致時,即會發生錯誤。

2)在普通變數或下標變數作函數參數時,參數變數和傳入參數變數是由編譯系統分配的兩個不同的記憶體單元。在函數使用時發生的值傳送是把傳入參數變數的值賦予參數變數。在用陣列名稱作函數參數時,不是進行值的傳送,即不是把傳入參數的每一個元素的值都賦予參數的各個元素。因為實際上參數並不存在,編譯系統不為參數分配記憶體。那麼,資料的傳送是如何實現的呢?在我們曾介紹過,陣列名稱就是陣列的首位址。因此在陣列名稱作函數參數時所進行的傳送只是位址的傳送,也就是說把傳入參數的首位址賦予參數陣列名稱。參數陣列名稱取得該首位址之後,也就等於有了實在的陣列。實際上是參數和傳入參數為同一陣列,共同擁有一段記憶體空間。

上圖說明瞭這種情形。圖中設a為傳入參數,類型為整型。a佔有以2000為首位址的一塊記憶體區。b為參數陣列名稱。當發生函數使用時,進行位址傳送,把傳入參數a的首位址傳送給參數陣列名稱b,於是b也取得該地址2000。於是ab兩陣列共同佔有以2000為首位址的一段連續記憶體單元。從圖中還可以看出ab下標相同的元素實際上也占相同的兩個記憶體單元(整型陣列每個元素占二位元組)。例如a[0]b[0]都佔用20002001單元,當然a[0]等於b[0]。類推則有a[i]等於b[i]

【例8.8】陣列a中存放了一個學生5門課程的成績,求平均成績。

float aver(float a[5])

{

    int i;

    float av,s=a[0];

    for(i=1;i<5;i++)

            s=s+a[i];

    av=s/5;

    return av;

}

void main()

{

    float sco[5],av;

    int i;

    printf("\ninput 5 scores:\n");

    for(i=0;i<5;i++)

            scanf("%f",&sco[i]);

    av=aver(sco);

    printf("average score is %5.2f",av);

}

本程式首先定義了一個實數函數 aver,有一個參數為實數陣列 a,長度為5。在函數 aver 中,把各元素值相加求出平均值,返回給主函數。主函數 main 中首先完成陣列 sco 的輸入,然後以 sco 作為傳入參數使用 aver 函數,函數返回值送 av,最後輸出 av值。 從運行情況可以看出,程式實現了所要求的功能。

3) 前面已經討論過,在變數作函數參數時,所進行的值傳送是單向的。即只能從傳入參數傳向參數,不能從參數傳回傳入參數。參數的初值和傳入參數相同,而參數的值發生改變後,傳入參數並不變化,兩者的終值是不同的。而當用陣列名稱作函數參數時,情況則不同。由於實際上參數和傳入參數為同一陣列,因此當參數發生變化時,傳入參數也隨之變化。當然這種情況不能理解為發生了“雙向”的值傳遞。但從實際情況來看,使用函數之後傳入參數的值將由於參數值的變化而變化。為了說明這種情況,把例5.4改為例5.6的形式。

【例8.9】題目同8.7例。改用陣列名稱作函數參數。

void nzp(int a[5])

{

    int i;

    printf("\nvalues of array a are:\n");

    for(i=0;i<5;i++)

    {

         if(a[i]<0) a[i]=0;

         printf("%d ",a[i]);

    }

}

main()

{

    int b[5],i;

    printf("\ninput 5 numbers:\n");

    for(i=0;i<5;i++)

          scanf("%d",&b[i]);

    printf("initial values of array b are:\n");

    for(i=0;i<5;i++)

         printf("%d ",b[i]);

    nzp(b);

    printf("\nlast values of array b are:\n");

    for(i=0;i<5;i++)

          printf("%d ",b[i]);

}

本程式中函數 nzp 的參數為整數組a,長度為 5。主函數中傳入參數 b也為整型,長度也為 5。在主函數中首先輸入陣列b的值,然後輸出陣列 b的初始值。然後以陣列名稱 b為傳入參數使用nzp函數。在 nzp 中,按要求把負值單元清 0,並輸出參數 a 的值。 返回主函數之後,再次輸出陣列 b 的值。從運行結果可以看出,陣列 b 的初值和終值是不同的,陣列 b 的終值和陣列 a 是相同的。這說明傳入參數參數為同一陣列,它們的值同時得以改變。

用陣列名作為函數參數時還應注意以下幾點:

a.參數和傳入參數之間的類型必須一致,否則將引起錯誤。

b.參數和傳入參數的長度可以不相同,因為在使用時,只傳送首位位址而不檢查參數的長度。當參數數的長度與傳入參數長度不一致時,雖不至於出現語法錯誤(編譯能通過),但程式執行結果將與實際不符,這是應予以注意的。

【例8.10】如把例8.9修改如下:

void nzp(int a[8])

{

    int i;

    printf("\nvalues of array aare:\n");

    for(i=0;i<8;i++)

    {

      if(a[i]<0)a[i]=0;

      printf("%d ",a[i]);

    }

}

main()

{

    int b[5],i;

    printf("\ninput 5 numbers:\n");

    for(i=0;i<5;i++)

      scanf("%d",&b[i]);

    printf("initial values of array b are:\n");

    for(i=0;i<5;i++)

      printf("%d ",b[i]);

    nzp(b);

    printf("\nlast values of array b are:\n");

    for(i=0;i<5;i++)

      printf("%d ",b[i]);

}

 

本程式與例8.9程式比,nzp函數的參數組長度改為8,函數體中,for語句的迴圈條件也改為i<8。因此,參數 a 和參數 b 的長度不一致。編譯能夠通過,但從結果看,陣列a的元素a[5]a[6]a[7]顯然是無意義的。

c.在函數參數表中,允許不給出參數的長度,或用一個變數來表示陣列元素的個數。

例如,可以寫為:

void nzp(int a[])

或寫為

void nzp(int a[]int n)

其中參數a沒有給出長度,而由n值動態地表示陣列的長度。n的值由主調函數的傳入參數進行傳送。

由此,例8.10又可改為例8.11的形式。

【例8.11

void nzp(int a[],int n)

{

        int i;

        printf("\nvalues of array a are:\n");

        for(i=0;i<n;i++)

          {

         if(a[i]<0) a[i]=0;

         printf("%d ",a[i]);

          }

}

main()

{

        int b[5],i;

        printf("\ninput 5 numbers:\n");

        for(i=0;i<5;i++)

          scanf("%d",&b[i]);

        printf("initial values of array b are:\n");

        for(i=0;i<5;i++)

          printf("%d ",b[i]);

        nzp(b,5);

        printf("\nlast values of array b are:\n");

        for(i=0;i<5;i++)

          printf("%d ",b[i]);

}

 

    本程式nzp函數的參數 a沒有給出長度,由 n 動態確定該長度。在main函數中,函數使用語句為 nzp(b5),其中參數 5 將賦予參數 n作為參數的長度。

d.多維陣列也可以作為函數的參數。在函數定義時對參數可以指定每一維的長度,也可省去第一維的長度。因此,以下寫法都是合法的。

      int MA(int a[3][10])

int MA(int a[][10])