4 12 變數的儲存類別

2021-06-28 23:29:04 字數 3905 閱讀 3647

我們已經了解了變數的作用域。作用域是從空間的角度來分析的,分為全域性變數和區域性變數。

變數還有另一種屬性——

儲存期(storage duration,也稱生命期)

。儲存期是指變數在記憶體中的存在期間。這是從變數值存在的時間角度來分析的。儲存期可以分為靜態儲存期(static storage duration)和動態儲存期(dynamic storage duration)。這是由變數的靜態儲存方式和動態儲存方式決定的。

所謂靜態儲存方式是指在程式執行期間,系統對變數分配固定的儲存空間。而動態儲存方式則是在程式執行期間,系統對變數動態地分配儲存空間。

先看一下記憶體中的供使用者使用的儲存空間的情況。這個儲存空間可以分為三部分,即:

圖 4.13

資料分別存放在靜態儲存區和動態儲存區中。

全域性變數全部存放在靜態儲存區中,在程式開始執行時給全域性變數分配儲存單元,程式執行完畢就釋放這些空間。在程式執行過程中它們佔據固定的儲存單元,而不是動態地進行分配和釋放。

在動態儲存區中存放以下資料:

對以上這些資料,在函式呼叫開始時分配動態儲存空間,函式結束時釋放這些空間。

在程式執行過程中,這種分配和釋放是動態的,如果在乙個程式中兩次呼叫同一函式,則要進行兩次分配和釋放,而兩次分配給此函式中區域性變數的儲存空間位址可能是不相同的。

如果在乙個程式中包含若干個函式,每個函式中的區域性變數的儲存期並不等於整個程式的執行週期,它只是整個程式執行週期的一部分。根據函式呼叫的情況,系統對區域性變數動態地分配和釋放儲存空間。

在c++中變數除了有資料型別的屬性之外,還有儲存類別(storage class) 的屬性。儲存類別指的是資料在記憶體中儲存的方法。儲存方法分為靜態儲存和動態儲存兩大類。具體包含4種:

自動的(auto)

、靜態的(static)

、暫存器的(register)

和外部的(extern)

。根據變數的儲存類別,可以知道變數的作用域和儲存期。

函式中的區域性變數,如果不用關鍵字static加以宣告,編譯系統對它們是動態地分配儲存空間的。函式的形參和在函式中定義的變數(包括在復合語句中定義的變數)都屬此類。在呼叫該函式時,系統給形參和函式中定義的變數分配儲存空間,資料儲存在動態儲存區中。在函式呼叫結束時就自動釋放這些空間。如果是在復合語句中定義的變數,則在變數定義時分配儲存空間,在復合語句結束時自動釋放空間。因此這類區域性變數稱為

自動變數(auto variable)

。自動變數用關鍵字auto作儲存類別的宣告。例如:

int f(int a) //定義f函式,a為形參

儲存類別auto和資料型別int的順序任意。關鍵字auto可以省略,如果不寫auto,則系統把它預設為自動儲存類別,它屬於動態儲存方式。

程式中大多數變數屬於自動變數。本教程前面各章所介紹的例子中,在函式中定義的變數都沒有宣告為auto,其實都預設指定為自動變數。在函式體中以下兩種寫法作用相同:

auto int b, c=3;

int b, c=3;

有時希望函式中的區域性變數的值在函式呼叫結束後不消失而保留原值,即其占用的儲存單元不釋放,在下一次該函式呼叫時,該變數保留上一次函式呼叫結束時的值。這時就應該指定該區域性變數為

靜態區域性變數(static local variable)

。【例4.12】靜態區域性變數的值。

#include using namespace std;

int f(int a) //定義f函式,a為形參

int main( )

定義f和i是存放在暫存器的區域性變數,如果n的值大,則能節約許多執行時間。

在程式中定義暫存器變數對編譯系統只是建議性(而不是強制性)的。當今的優化編譯系統能夠識別使用頻繁的變數,自動地將這些變數放在暫存器中。

全域性變數(外部變數)是在函式的外部定義的,它的作用域為從變數的定義處開始,到本程式檔案的末尾。在此作用域內,全域性變數可以為本檔案中各個函式所引用。編譯時將全域性變數分配在靜態儲存區。

有時需要用extern來宣告全域性變數,以擴充套件全域性變數的作用域。

1) 在乙個檔案內宣告全域性變數

如果外部變數不在檔案的開頭定義,其有效的作用範圍只限於定義處到檔案終了。如果在定義點之前的函式想引用該全域性變數,則應該在引用之前用關鍵字extern對該變數作外部變數宣告,表示該變數是乙個將在下面定義的全域性變數。有了此宣告,就可以從宣告處起,合法地引用該全域性變數,這種宣告稱為

提前引用宣告

。【例4.14】用extern對外部變數作提前引用宣告,以擴充套件程式檔案中的作用域。

#include using namespace std;

int max(int,int); //函式宣告

void main( )

執行結果如下:

15在main後面定義了全域性變數a,b,但由於全域性變數定義的位置在函式main之後,因此如果沒有程式的第5行,在main函式中是不能引用全域性變數a和b的。現在我們在main函式第2行用extern對a和b作了提前引用宣告,表示a和b是將在後面定義的變數。這樣在main函式中就可以合法地使用全域性變數a和b了。如果不作extern宣告,編譯時會出錯,系統認為a和b未經定義。一般都把全域性變數的定義放在引用它的所有函式之前,這樣可以避免在函式中多加乙個extern宣告。

2) 在多檔案的程式中宣告外部變數

如果乙個程式包含兩個檔案,在兩個檔案中都要用到同乙個外部變數num,不能分別在兩個檔案中各自定義乙個外部變數num。正確的做法是:在任乙個檔案中定義外部變數num,而在另一檔案中用extern對num作外部變數宣告。即

extern int num;

編譯系統由此知道num是乙個已在別處定義的外部變數,它先在本檔案中找有無外部變數num,如果有,則將其作用域擴充套件到本行開始(如上節所述),如果本檔案中無此外部變數,則在程式連線時從其他檔案中找有無外部變數num,如果有,則把在另一檔案中定義的外部變數num的作用域擴充套件到本檔案,在本檔案中可以合法地引用該外部變數num。

分析下例:

filel.cpp

extern int a,b;

int main()

file2.cpp

int as3,b=4;

┆在源程式檔案ffle2.cpp中定義了整型變數a和b,並賦了初值。在filel.cpp中用extern宣告外部變數a和b,未賦值。在編譯連線成乙個程式後,file2.cpp中的a和b的作用域擴充套件到file2.cpp檔案中,因此main函式中的cout語句輸出a和b的值為3和4。

用extern擴充套件全域性變數的作用域,雖然能為程式設計帶來方便,但應十分慎重,因為在執行乙個檔案中的函式時,可能會改變了該全域性變數的值,從而會影響到另一檔案中的函式執行結果。

有時在程式設計中希望某些外部變數只限於被本檔案引用,而不能被其他檔案引用。這時可以在定義外部變數時加乙個static宣告。

例如:file1.cpp

static int a=3;

int main ( )

file2.cpp

extern int a;

int fun (int n)

在filel.cpp中定義了乙個全域性變數a,但它用static宣告,因此只能用於本檔案,雖然 在cpp檔案中用了「extern int a;」,但file2.cpp檔案中仍然無法使用filel.cpp中的全域性變數a。

這種加上static宣告、只能用於本檔案的外部變數(全域性變數)稱為靜態外部變數。這就為程式的模組化、通用性提供了方便。如果已知道其他檔案不需要引用本檔案的全域性變數,可以對本檔案中的全域性變數都加上static,成為靜態外部變數,以免被其他檔案誤用。

需要指出,不要誤認為用static宣告的外部變數才採用靜態儲存方式(存放在靜態儲存區中),而不加static的是動態儲存(存放在動態儲存區)。實際上,兩種形式的外部變數都用靜態儲存方式,只是作用範圍不同而已,都是在編譯時分配記憶體的。

變數的儲存類別

從變數的作用域來分,變數可以分為全域性變數和區域性變數。在乙個函式內部定義的變數是區域性變數,它只是在本函式範圍內有效,在此函式外不能使用這些變數的。全域性變數可以供所有函式共用,它的有效範圍為從定義變數的位置開始到本原始檔結束。全域性變數的優點是 可以減少函式實參和形參的個數,從而減少記憶體空間以...

變數的儲存類別

儲存類別 是指資料在記憶體中的儲存方式 1 供使用者使用的儲存空間 程式區靜態儲存區 編譯時候分配空間,程式結束釋放空間。存放全域性變數 動態儲存區 定義時動態分配空間,對應函式完成時就釋放空間,再呼叫時又重新動態分配空間。存放auto型別區域性變數 2 儲存型別 auto,static,regis...

變數的儲存類別

普通區域性變數 自動變數 在乙個函式內定義,只在函式範圍內有效。在復合語句中定義,只在符合語句中有效。隨著函式呼叫的結束或復合語句的結束而消亡。如果沒有賦初值,則內容為隨機值。2.靜態區域性變數static 作用域 定義的函式內有效。生命週期 在定義的整個週期,靜態區域性變數始終從在著,即使退出函式...