3. 前面已經討論過,在變量作函數參數時,所進行的值傳送是單向的。即只能從實參傳向形參,不能從形參傳回實參。形參的初值和實參相同, 而形參的值發生改變后,實參并不變化, 兩者的終值是不同的。例5.3證實了這個結論。 而當用數組名作函數參數時,情況則不同。 由于實際上形參和實參為同一數組, 因此當形參數組發生變化時,實參數組也隨之變化。 當然這種情況不能理解為發生了“雙向”的值傳遞。但從實際情況來看,調用函數之后實參數組的值將由于形參數組值的變化而變化。為了說明這種情況,把例5.4改為例5.6的形式。[例5.6]題目同5.4例。改用數組名作函數參數。 void nzp(int a[5]) { int i; printf("values of array a are:"); for(i=0;i<5;i++) { if(a[i]<0) a[i]=0; printf("%d ",a[i]); } } main() { int b[5],i; printf("input 5 numbers:"); for(i=0;i<5;i++) scanf("%d",&b[i]); printf("initial values of array b are:"); for(i=0;i<5;i++) printf("%d ",b[i]); nzp(b); printf("last values of array b are:"); for(i=0;i<5;i++) printf("%d ",b[i]); } void nzp(int a[5]) { …… } main() { int b[5],i; …… nzp(b); …… } 本程序中函數nzp的形參為整數組a,長度為 5。 主函數中實參數組b也為整型,長度也為5。在主函數中首先輸入數組b的值,然后輸出數組b的初始值。 然后以數組名b為實參調用nzp函數。在nzp中,按要求把負值單元清0,并輸出形參數組a的值。 返回主函數之后,再次輸出數組b的值。從運行結果可以看出,數組b 的初值和終值是不同的,數組b 的終值和數組a是相同的。這說明實參形參為同一數組,它們的值同時得以改變。 用數組名作為函數參數時還應注重以下幾點: a. 形參數組和實參數組的類型必須一致,否則將引起錯誤。 b. 形參數組和實參數組的長度可以不相同,因為在調用時,只傳送首地址而不檢查形參數組的長度。當形參數組的長度與實參數組不一致時,雖不至于出現語法錯誤(編譯能通過),但程序執行結果將與實際不符,這是應予以注重的。如把例5.6修改如下:
void nzp(int a[8]) { int i; printf("values of array aare:"); for(i=0;i<8;i++)
} main() { int b[5],i; printf("input 5 numbers:"); for(i=0;i<5;i++) scanf("%d",&b[i]); printf("initial values of array b are:"); for(i=0;i<5;i++) printf("%d",b[i]); nzp(b); printf("last values of array b are:"); for(i=0;i<5;i++) printf("%d",b[i]); } 本程序與例5.6程序比,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的值由主調函數的實參進行傳送。 由此,例5.6又可改為例5.7的形式。 [例5.7]void nzp(int a[],int n) { int i; printf("values of array a are:"); for(i=0;i<n;i++) { if(a[i]<0) a[i]=0; printf("%d ",a[i]); } } main() { int b[5],i; printf("input 5 numbers:"); for(i=0;i<5;i++) scanf("%d",&b[i]); printf("initial values of array b are:"); for(i=0;i<5;i++) printf("%d ",b[i]); nzp(b,5); printf("last values of array b are:"); for(i=0;i<5;i++) printf("%d ",b[i]); } void nzp(int a[],int n) { …… } main()
本程序nzp函數形參數組a沒有給出長度,由n 動態確定該長度。在main函數中,函數調用語句為nzp(b,5),其中實參5將賦予形參n作為形參數組的長度。 d. 多維數組也可以作為函數的參數。 在函數定義時對形參數組可以指定每一維的長度,也可省去第一維的長度。因此,以下寫法都是合法的。 int MA(int a[3][10]) 或 int MA(int a[][10])
局部變量也稱為內部變量。局部變量是在函數內作定義說明的。其作用域僅限于函數內, 離開該函數后再使用這種變量是非法的。 例如: int f1(int a) /*函數f1*/ { int b,c; …… }a,b,c作用域 int f2(int x) /*函數f2*/ { int y,z; }x,y,z作用域 main() { int m,n; } m,n作用域 在函數f1內定義了三個變量,a為形參,b,c為一般變量。在 f1的范圍內a,b,c有效,或者說a,b,c變量的作用域限于f1內。同理,x,y,z的作用域限于f2內。 m,n的作用域限于main函數內。關于局部變量的作用域還要說明以下幾點:
在C語言中,對變量的存儲類型說明有以下四種: auto 自動變量 register 寄存器變量 extern 外部變量 static 靜態變量 自動變量和寄存器變量屬于動態存儲方式, 外部變量和靜態變量屬于靜態存儲方式。在介紹了變量的存儲類型之后, 可以知道對一個變量的說明不僅應說明其數據類型,還應說明其存儲類型。 因此變量說明的完整形式應為: 存儲類型說明符 數據類型說明符 變量名,變量名…; 例如: static int a,b; 說明a,b為靜態類型變量 auto char c1,c2; 說明c1,c2為自動字符變量 static int a[5]=; 說明a為靜整型數組 extern int x,y; 說明x,y為外部整型變量 下面分別介紹以上四種存儲類型:
一、自動變量的類型說明符為auto。 這種存儲類型是C語言程序中使用最廣泛的一種類型。C語言規定, 函數內凡未加存儲類型說明的變量均視為自動變量, 也就是說自動變量可省去說明符auto。 在前面各章的程序中所定義的變量凡未加存儲類型說明符的都是自動變量。例如: { int i,j,k; char c; …… }等價于: { auto int i,j,k; auto char c; …… } 自動變量具有以下特點: 1. 自動變量的作用域僅限于定義該變量的個體內。在函數中定義的自動變量,只在該函數內有效。在復合語句中定義的自動變量只在該復合語句中有效。 例如: int kv(int a) { auto int x,y; { auto char c; } /*c的作用域*/ …… } /*a,x,y的作用域*/
2. 自動變量屬于動態存儲方式,只有在使用它,即定義該變量的函數被調用時才給它分配存儲單元,開始它的生存期。函數調用結束,釋放存儲單元,結束生存期。因此函數調用結束之后,自動變量的值不能保留。在復合語句中定義的自動變量,在退出復合語句后也不能再使用,否則將引起錯誤。例如以下程序: main() { auto int a,s,p; printf("input a number:"); scanf("%d",&a); if(a>0) printf("s=%d p=%d",s,p); } { auto int a; printf("input a number:"); scanf("%d",&a); if(a>0){ auto int s,p; s=a+a; p=a*a; } printf("s=%d p=%d",s,p); } s,p是在復合語句內定義的自動變量,只能在該復合語句內有效。而程序的第9行卻是退出復合語句之后用printf語句輸出s,p的值,這顯然會引起錯誤。
3. 由于自動變量的作用域和生存期都局限于定義它的個體內( 函數或復合語句內), 因此不同的個體中答應使用同名的變量而不會混淆。 即使在函數內定義的自動變量也可與該函數內部的復合語句中定義的自動變量同名。例5.14表明了這種情況。 [例5.14] main() { auto int a,s=100,p=100; printf("input a number:"); scanf("%d",&a); if(a>0) { auto int s,p; s=a+a; p=a*a; printf("s=%d p=%d",s,p); } printf("s=%d p=%d",s,p); } 本程序在main函數中和復合語句內兩次定義了變量s,p為自動變量。按照C語言的規定,在復合語句內,應由復合語句中定義的s,p起作用,故s的值應為a+ a,p的值為a*a。退出復合語句后的s,p 應為main所定義的s,p,其值在初始化時給定,均為100。從輸出結果可以分析出兩個s和兩個p雖變量名相同, 但卻是兩個不同的變量。