C語言中全部變量都有本身的做用域,申明變量的類型不一樣,其做用域也不一樣。C語言中的變量,按照做用域的範圍可分爲兩種, 即局部變量和全局變量。 數組
局部變量也稱爲內部變量。局部變量是在函數內做定義說明的。其做用域僅限於函數內, 離開該函數後再使用這種變量是非法的。模塊化
例如:函數
int f1(int a) /*函數f1*/ …… |
int f2(int x) /*函數f2*/ …… |
f1內定義了三個變量,a爲形參,b,c爲通常變量。在 f1的範圍內a,b,c有效,或者說a,b,c變量的做用域限於f1內。內存 |
f2內定義了三個變量,x爲形參,y,z爲通常變量。在 f2的範圍內x,y,z有效,或者說x,y,z變量的做用域限於f2內。ci |
關於局部變量的做用域還要說明如下幾點:作用域
主函數中定義的變量也只能在主函數中使用,不能在其它函數中使用。同時,主函數中也不能使用其它函數中定義的變量。由於主函數也是一個函數,它與其它函數是平行關係。
形參變量是屬於被調函數的局部變量,實參變量是屬於主調函數的局部變量。
容許在不一樣的函數中使用相同的變量名,它們表明不一樣的對象,分配不一樣的單元,互不干擾,也不會發生混淆。雖然容許在不一樣的函數中使用相同的變量名,可是爲了使程序明瞭易懂,不提倡在不一樣的函數中使用相同的變量名。
int a,b; /*外部變量*/ |
float x,y; /*外部變量*/ |
全局變量也稱爲外部變量,它是在函數外部定義的變量。 它不屬於哪個函數,它屬於一個源程序文件。其做用域是整個源程序。在函數中使用全局變量,通常應做全局變量說明。 只有在函數內通過說明的全局變量才能使用。全局變量的說明符爲extern。 但在一個函數以前定義的全局變量,在該函數內使用可再也不加以說明。 例如:
從上例能夠看出a、b、x、y 都是在函數外部定義的外部變量,都是全局變量。
對於全局變量還有如下幾點說明:
對於局部變量的定義和說明,能夠不加區分。而對於外部變量則否則,外部變量的定義和外部變量的說明並非一回事。外部變量定義必須在全部的函數以外,且只能定義一次。其通常形式爲: [extern] 類型說明符 變量名,變量名… 其中方括號內的extern能夠省去不寫。
例如: int a,b;
等效於:
extern int a,b;
而外部變量說明出如今要使用該外部變量的各個函數內,在整個程序內,可能出現屢次,外部變量說明的通常形式爲: extern 類型說明符 變量名,變量名,…; 外部變量在定義時就已分配了內存單元,外部變量定義可做初始賦值,外部變量說明不能再賦初始值,只是代表在函數內要使用某外部變量。
外部變量可增強函數模塊之間的數據聯繫,可是又使函數要依賴這些變量,於是使得函數的獨立性下降。從模塊化程序設計的觀點來看這是不利的, 所以在沒必要要時儘可能不要使用全局變量。
在同一源文件中,容許全局變量和局部變量同名。在局部變量的做用域內,全局變量不起做用。
int vs(int l,int w) { extern int h; int v; v=l*w*h; return v; } main() { extern int w,h; int l=5; printf("v=%d",vs(l,w)); } int l=3,w=4,h=5;
本例程序中,外部變量在最後定義, 所以在前面函數中對要用的外部變量必須進行說明。外部變量l,w和vs函數的形參l,w同名。外部變量都做了初始賦值,mian函數中也對l做了初始化賦值。執行程序時,在printf語句中調用vs函數,實參l的值應爲main中定義的l值,等於5,外部變量l在main內不起做用;實參w的值爲外部變量w的值爲4,進入vs後這兩個值傳送給形參l,wvs函數中使用的h 爲外部變量,其值爲5,所以v的計算結果爲100,返回主函數後輸出。
變量的存儲類型決定了各類變量的做用域不一樣。所謂存儲類型是指變量佔用內存空間的方式,也稱爲存儲方式。變量的存儲方式可分爲「靜態存儲」和「動態存儲」兩種。
靜態存儲變量一般是在變量定義時就分定存儲單元並一直保持不變, 直至整個程序結束。動態存儲變量是在程序執行過程當中,使用它時才分配存儲單元, 使用完畢當即釋放。 典型的例子是函數的形式參數,在函數定義時並不給形參分配存儲單元,只是在函數被調用時,才予以分配, 調用函數完畢當即釋放。若是一個函數被屢次調用,則反覆地分配、 釋放形參變量的存儲單元。從以上分析可知, 靜態存儲變量是一直存在的, 而動態存儲變量則時而存在時而消失。咱們又把這種因爲變量存儲方式不一樣而產生的特性稱變量的生存期。 生存期表示了變量存在的時間。 生存期和做用域是從時間和空間這兩個不一樣的角度來描述變量的特性,這二者既有聯繫,又有區別。 一個變量究竟屬於哪種存儲方式, 並不能僅從其做用域來判斷,還應有明確的存儲類型說明。
在C語言中,對變量的存儲類型說明有如下四種:
auto 自動變量
register 寄存器變量
extern 外部變量
static 靜態變量
自動變量和寄存器變量屬於動態存儲方式,外部變量和靜態變量屬於靜態存儲方式。在介紹了變量的存儲類型以後, 能夠知道對一個變量的說明不只應說明其數據類型,還應說明其存儲類型。所以變量說明的完整形式應爲: 存儲類型說明符 數據類型說明符 變量名,變量名…; 例如:
static int a,b; 說明a,b爲靜態類型變量
auto char c1,c2; 說明c1,c2爲自動字符變量
static int a[5]={1,2,3,4,5}; 說明a爲靜整型數組
extern int x,y; 說明x,y爲外部整型變量
下面分別介紹以上四種存儲類型:
1、自動變量的類型說明符爲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("/ninput a number:/n"); scanf("%d",&a); if(a>0){ s=a+a; p=a*a; } printf("s=%d p=%d/n",s,p); } { auto int a; printf("/ninput a number:/n"); scanf("%d",&a); if(a>0){ auto int s,p; s=a+a; p=a*a; } printf("s=%d p=%d/n",s,p); }
s,p是在複合語句內定義的自動變量,只能在該複合語句內有效。而程序的第9行倒是退出複合語句以後用printf語句輸出s,p的值,這顯然會引發錯誤。
3. 因爲自動變量的做用域和生存期都侷限於定義它的個體內( 函數或複合語句內), 所以不一樣的個體中容許使用同名的變量而不會混淆。 即便在函數內定義的自動變量也可與該函數內部的複合語句中定義的自動變量同名。例5.14代表了這種狀況。
main() { auto int a,s=100,p=100; printf("/ninput a number:/n"); scanf("%d",&a); if(a>0) { auto int s,p; s=a+a; p=a*a; printf("s=%d p=%d/n",s,p); } printf("s=%d p=%d/n",s,p); }
本程序在main函數中和複合語句內兩次定義了變量s,p爲自動變量。按照C語言的規定,在複合語句內,應由複合語句中定義的s,p起做用,故s的值應爲a+ a,p的值爲a*a。退出複合語句後的s,p應爲main所定義的s,p,其值在初始化時給定,均爲100。從輸出結果能夠分析出兩個s和兩個p雖變量名相同, 但倒是兩個不一樣的變量。
4. 對構造類型的自動變量如數組等,不可做初始化賦值。
2、外部變量的類型說明符爲extern
在前面介紹全局變量時已介紹過外部變量。這裏再補充說明外部變量的幾個特色:
1. 外部變量和全局變量是對同一類變量的兩種不一樣角度的提法。全局變量是從它的做用域提出的,外部變量從它的存儲方式提出的,表示了它的生存期。
2. 當一個源程序由若干個源文件組成時, 在一個源文件中定義的外部變量在其它的源文件中也有效。例若有一個源程序由源文件F1.C和F2.C組成:
F1.C
int a,b; /*外部變量定義*/ char c; /*外部變量定義*/ main() { …… }
F2.C
extern int a,b; /*外部變量說明*/ extern char c; /*外部變量說明*/ func (int x,y) { …… }
在F1.C和F2.C兩個文件中都要使用a,b,c三個變量。在F1.C文件中把a,b,c都定義爲外部變量。在F2.C文件中用extern把三個變量說明爲外部變量,表示這些變量已在其它文件中定義,並把這些變量的類型和變量名,編譯系統再也不爲它們分配內存空間。 對構造類型的外部變量, 如數組等能夠在說明時做初始化賦值,若不賦初值,則系統自動定義它們的初值爲0。
3、靜態變量
靜態變量的類型說明符是static。 靜態變量固然是屬於靜態存儲方式,可是屬於靜態存儲方式的量不必定就是靜態變量, 例如外部變量雖屬於靜態存儲方式,但不必定是靜態變量,必須由static加以定義後才能成爲靜態外部變量,或稱靜態全局變量。 對於自動變量,前面已經介紹它屬於動態存儲方式。 可是也能夠用static定義它爲靜態自動變量,或稱靜態局部變量,從而成爲靜態存儲方式。
由此看來, 一個變量可由static進行再說明,並改變其原有的存儲方式。
1. 靜態局部變量
在局部變量的說明前再加上static說明符就構成靜態局部變量。
例如:
static int a,b; static float array[5]={1,2,3,4,5};
靜態局部變量屬於靜態存儲方式,它具備如下特色:
(1)靜態局部變量在函數內定義,但不象自動變量那樣,當調用時就存在,退出函數時就消失。靜態局部變量始終存在着,也就是說它的生存期爲整個源程序。
(2)靜態局部變量的生存期雖然爲整個源程序,可是其做用域仍與自動變量相同,即只能在定義該變量的函數內使用該變量。退出該函數後, 儘管該變量還繼續存在,但不能使用它。
(3)容許對構造類靜態局部量賦初值。在數組一章中,介紹數組初始化時已做過說明。若未賦以初值,則由系統自動賦以0值。
(4)對基本類型的靜態局部變量若在說明時未賦以初值,則系統自動賦予0值。而對自動變量不賦初值,則其值是不定的。 根據靜態局部變量的特色, 能夠看出它是一種生存期爲整個源程序的量。雖然離開定義它的函數後不能使用,但如再次調用定義它的函數時,它又可繼續使用, 並且保存了前次被調用後留下的值。 所以,當屢次調用一個函數且要求在調用之間保留某些變量的值時,可考慮採用靜態局部變量。雖然用全局變量也能夠達到上述目的,但全局變量有時會形成意外的反作用,所以仍以採用局部靜態變量爲宜。
[例5.15]
main() { int i; void f(); /*函數說明*/ for(i=1;i<=5;i++) f(); /*函數調用*/ } void f() /*函數定義*/ { auto int j=0; ++j; printf("%d/n",j); }
程序中定義了函數f,其中的變量j 說明爲自動變量並賦予初始值爲0。當main中屢次調用f時,j均賦初值爲0,故每次輸出值均爲1。如今把j改成靜態局部變量,程序以下:
main() { int i; void f(); for (i=1;i<=5;i++) f(); } void f() { static int j=0; ++j; printf("%d/n",j); } void f() { static int j=0; ++j; printf("%d/n",j); }
因爲j爲靜態變量,能在每次調用後保留其值並在下一次調用時繼續使用,因此輸出值成爲累加的結果。讀者可自行分析其執行過程。
2.靜態全局變量
全局變量(外部變量)的說明以前再冠以static 就構成了靜態的全局變量。全局變量自己就是靜態存儲方式, 靜態全局變量固然也是靜態存儲方式。 這二者在存儲方式上並沒有不一樣。這二者的區別雖在於非靜態全局變量的做用域是整個源程序, 當一個源程序由多個源文件組成時,非靜態的全局變量在各個源文件中都是有效的。 而靜態全局變量則限制了其做用域, 即只在定義該變量的源文件內有效, 在同一源程序的其它源文件中不能使用它。因爲靜態全局變量的做用域侷限於一個源文件內,只能爲該源文件內的函數公用, 所以能夠避免在其它源文件中引發錯誤。從以上分析能夠看出, 把局部變量改變爲靜態變量後是改變了它的存儲方式即改變了它的生存期。把全局變量改變爲靜態變量後是改變了它的做用域, 限制了它的使用範圍。所以static 這個說明符在不一樣的地方所起的做用是不一樣的。應予以注意。
4、寄存器變量
上述各種變量都存放在存儲器內, 所以當對一個變量頻繁讀寫時,必需要反覆訪問內存儲器,從而花費大量的存取時間。 爲此,C語言提供了另外一種變量,即寄存器變量。這種變量存放在CPU的寄存器中,使用時,不須要訪問內存,而直接從寄存器中讀寫, 這樣可提升效率。寄存器變量的說明符是register。 對於循環次數較多的循環控制變量及循環體內反覆使用的變量都可定義爲寄存器變量。
求1到200全部數之和。
main() { register i,s=0; for(i=1;i<=200;i++) s=s+i; printf("s=%d/n",s); }
本程序循環200次,i和s都將頻繁使用,所以可定義爲寄存器變量。對寄存器變量還要說明如下幾點: 1. 只有局部自動變量和形式參數才能夠定義爲寄存器變量。由於寄存器變量屬於動態存儲方式。凡須要採用靜態存儲方式的量不能定義爲寄存器變量。 2. 在Turbo C,MS C等微機上使用的C語言中, 其實是把寄存器變量當成自動變量處理的。所以速度並不能提升。 而在程序中容許使用寄存器變量只是爲了與標準C保持一致。3. 即便能真正使用寄存器變量的機器,因爲CPU 中寄存器的個數是有限的,所以使用寄存器變量的個數也是有限的。