一、作用域和生存期
C程序的標識符作用域有三種:局部、全局、文件。標識符的作用域決定了程序中的哪些語句可以使用它,換句話說,就是標識符在程序其他部分的可見性。通常,標識符的作用域都是通過它在程序中的位置隱式說明的。
1.局部作用域
前面各個例子中的變量都是局部作用域,他們都是聲明在函數內部,無法被其他函數的代碼所訪問。函數的形式參數的作用域也是局部的,它們的作用范圍僅限於函數內部所用的語句塊。
void add(int);
main()
{
int num=5;
add(num);
printf(%d\n,num); /*輸出5*/
}
void add(int num)
{
num++;
printf(%d\n,num); /*輸出6*/
}
上面例子裡的兩個num變量都是局部變量,只在本身函數裡可見。前面我們說了,在兩個函數出現同名的變量不會互相干擾,就是這個道理。所以上面的兩個輸出,在主函數裡仍然是5,在add()函數裡輸出是6。
2.全局作用域
對於具有全局作用域的變量,我們可以在程序的任何位置訪問它們。當一個變量是在所有函數的外部聲明,也就是在程序的開頭聲明,那麼這個變量就是全局變量。
void add(int);
int num;
main()
{
int n=5;
add(n);
printf(%d\n,num); /*輸出6*/
}
void add(num) /*形式參數沒有指定類型*/
{
num++;
printf(%d\n,num); /*輸出6*/
}
上面的main()和add()裡面,並沒有聲明num,但是在最後輸出的時候卻要求輸出num,這是由於在程序的開始聲明了num是全局變量,也就是在所有函數裡都可以使用這個變量。這時候一個函數裡改變了變量的值,其他函數裡的值也會出現影響。上面的例子輸出都是6,因為在add()函數裡改變了num的值,由於num是全局變量,就好象它們兩個函數共用一個變量,所以在main()函數裡的num也隨之改變了。
3.文件作用域
在很多C語言書上,都沒有說明文件作用域,或者只是略微的提到,其實文件作用域在較大程序中很有作用(在多文件系統中)。文件作用域是指外部標識符僅在聲明它的同一個轉換單元內的函數匯總可見。所謂轉換單元是指定義這些變量和函數的源代碼文件(包括任何通過#include指令包含的源代碼文件)。static存儲類型修飾符指定了變量具有文件作用域。
static int num;
static void add(int);
main()
{
scanf(%d,&num);
add(num)
printf(%d\n,num);
}
void add(num)
{
num++;
}
上面的程序中變量num和函數add()在聲明是采用了static存儲類型修飾符,這使得它們具有文件作用域,僅愛定義它們的文件內可見。
由於我們提到的大多數程序都只有一個編譯文件組成,所以這種寫法沒有實際意義。但是實際工程上的文件有很多,它們不是由一個人寫成的,由很多人共同完成,這些文件都是各自編譯的,這難免使得某些人使用了一樣的全局變量名,那麼為了以後程序中各自的變量和函數不互相干擾,就可以使用static修飾符,這樣在連接到同一個程序的其他代碼文件而言就是不可見的。
二、變量存儲類型
前面我們說了,聲明變量時用如下類似的形式:
int num;
float total;
它們都沒有存儲類型修飾符,我們在聲明時也可以通過存儲類型修飾符來告訴編譯器將要處理什麼類型的變量。存儲類型有以下四種:自動(auto)、靜態(static)、外部(extern)、寄存器(regiser)。
1.自動存儲類型
自動存儲類型修飾符指定了一個局部變量為自動的,這意味著,每次執行到定義該變量的語句塊時,都將會為該變量在內存中產生一個新的拷貝,並對其進行初始化。實際上,如果不特別指明,局部變量的存儲類型就默認為自動的,因此,加不加auto都可以。
main()
{
auto int num=5;
printf(%d\n,num);
}
在這個例子中,不論變量num的聲明是否包含關鍵字auto,代碼的執行效果都是一樣的。函數的形式參數存儲類型默認也是自動的。
2.靜態存儲變量
前面已經使用了static關鍵字,但是對於局部變量,靜態存儲類型的意義是不一樣的,這時,它是和自動存儲類型相對而言的。靜態局部變量的作用域仍然近局限於聲明它的語句塊中,但是在語句塊執行期間,變量將始終保持它的值。而且,初始化值只在語句塊第一次執行是起作用。在隨後的運行過程中,變量將保持語句塊上一次執行時的值。看下面兩個對應的程序:
/*1.C*/ /*2.C*/
int add(); int add();
main() main()
{ {
int result; int result;
result=add() result=add();
printf(%d ,result); printf(%d ,result);
result=add(); result=add();
printf(%d ,result); printf(%d ,result);
result=add(); result=add();
printf(%d,result); printf(%d,result);
} }
int add() int add()
{ {
int num=50; static int num=50;
num++; num++;
return num; return num;
} }
上面兩個源文件,只有函數add()裡的變量聲明有所不同,一個是自動存儲類型,一個是靜態存儲類型。
對於1.C文件,輸出結果為51 51 51;這很好理解,每次初始值都是50,然後加1上來。
對於2.C文件,輸出結果為51 52 53;這是由於變量是靜態的,只在第一次初始化了50,以後都是使用上次的結果值。當第一次調用add()時,初始化為50,然後加1,輸出為51;當第二次調用時,就不初始化了,這時num的值為上次的51,然後加1,輸出52;當第三次調用時,num為52,加1就是53了。
比較就會發現它們的不同之處了。靜態變量在下一節要說的遞歸函數中經常使用到。
當第一次不指明靜態變量的初始值時,默認為0。
下面舉一個例子,把我們說到的靜態變量理解一下。
求1+2+……+100的值
void add();