1. 程式人生 > >C++變數的儲存類別

C++變數的儲存類別

動態儲存方式與靜態儲存方式

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

變數還有另一種屬性——儲存期(storage duration,也稱生命期)。儲存期是指變數在記憶體中的存在期間。這是從變數值存在的時間角度來分析的。儲存期可以分為靜態儲存期(static storage duration)和動態儲存期(dynamic storage duration)。這是由變數的靜態儲存方式和動態儲存方式決定的。

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

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

  • 程式區
  • 靜態儲存區
  • 動態儲存區

圖 4.13

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

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

  • 函式形式引數。在呼叫函式時給形參分配儲存空間。
  • 函式中的自動變數(未加static宣告的區域性變數,詳見後面的介紹)。
  • 函式呼叫時的現場保護和返回地址等。

對以上這些資料,在函式呼叫開始時分配動態儲存空間,函式結束時釋放這些空間。在程式執行過程中,這種分配和釋放是動態的,如果在一個程式中兩次呼叫同一函式,則要進行兩次分配和釋放,而兩次分配給此函式中區域性變數的儲存空間地址可能是不相同的。

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

在C++中變數除了有資料型別的屬性之外,還有儲存類別(storage class) 的屬性。儲存類別指的是資料在記憶體中儲存的方法。儲存方法分為靜態儲存和動態儲存兩大類。具體包含4種:自動的(auto)靜態的(static)暫存器的(register)外部的(extern)。根據變數的儲存類別,可以知道變數的作用域和儲存期。

自動變數

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

。自動變數用關鍵字auto作儲存類別的宣告。例如:
int f(int a) //定義f函式,a為形參
{
auto int b, c=3; //定義b和c為整型的自動變數
}

儲存類別auto和資料型別int的順序任意。關鍵字auto可以省略,如果不寫auto,則系統把它預設為自動儲存類別,它屬於動態儲存方式。程式中大多數變數屬於自動變數。本教程前面各章所介紹的例子中,在函式中定義的變數都沒有宣告為auto,其實都預設指定為自動變數。在函式體中以下兩種寫法作用相同:
auto int b, c=3;
int b, c=3;

用static宣告靜態區域性變數

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

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

  1. #include <iostream>
  2. using namespace std;
  3. int f(int a) //定義f函式,a為形參
  4. {
  5. auto int b=0; //定義b為自動變數
  6. static int c=3; //定義c為靜態區域性變數
  7. b=b+1;
  8. c=c+1;
  9. return a+b+c;
  10. }
  11. int main( )
  12. {
  13. int a=2,i;
  14. for(i=0;i<3;i++)
  15. cout<<f(a)<<” “;
  16. cout<<endl;
  17. return 0;
  18. }

執行結果為:
7 8 9

先後3次呼叫f函式時,b和c的值如書中表4.1所示。

表 4.1 呼叫函式時自動變數和靜態區域性變數的值
第幾次呼叫 呼叫時初值 呼叫結束時的值
自動變數b 靜態區域性變數c b c a + b+c
第1次 0 3 1 4 7
第2次 0 4 1 5 8
第3次 0 5 1 6 9

圖 4.14

對靜態區域性變數的說明:

  1. 靜態區域性變數在靜態儲存區內分配儲存單元。在程式整個執行期間都不釋放。而自動變數(即動態區域性變數)屬於動態儲存類別,儲存在動態儲存區空間(而不是靜態儲存區空間),函式呼叫結束後即釋放。
  2. 為靜態區域性變數賦初值是在編譯時進行值的,即只賦初值一次,在程式執行時它已有初值。以後每次呼叫函式時不再重新賦初值而只是保留上次函式呼叫結束時的值。而為自動變數賦初值,不是在編譯時進行的,而是在函式呼叫時進行,每呼叫一次函式重新給一次初值,相當於執行一次賦值語句。
  3. 如果在定義區域性變數時不賦初值的話,對靜態區域性變數來說,編譯時自動賦初值0(對數值型變數)或空字元(對字元型變數)。而對自動變數來說,如果不賦初值,則它的值是一個不確定的值。這是由於每次函式呼叫結束後儲存單元已釋放,下次呼叫時又重新另分配儲存單元,而所分配的單元中的值是不確定的。
  4. 雖然靜態區域性變數在函式呼叫結束後仍然存在,但其他函式是不能引用它的,也就是說,在其他函式中它是“不可見”的。

在什麼情況下需要用區域性靜態變數呢?

1) 需要保留函式上一次呼叫結束時的值。例如可以用下例中的方法求n!。

【例4.13】輸出1~5的階乘值(即1!,2!,3!,4!,5!)。

  1. #include <iostream>
  2. using namespace std;
  3. int fac(int); //函式宣告
  4. int main( )
  5. {
  6. int i;
  7. for(i=1;i<=5;i++)
  8. cout<<i<<“!=”<<fac(i)<<endl;
  9. return 0;
  10. }
  11. int fac(int n)
  12. {
  13. static int f=1; //f為靜態區域性變數,函式結束時f的值不釋放
  14. f=f*n; //在f原值基礎上乘以n
  15. return f;
  16. }

執行結果為
1!=1
2!=2
3!=6
4!=24
5!=120
每次呼叫fac(i),就輸出一個i,同時保留這個i!的值,以便下次再乘(i+1)。

2) 如果初始化後,變數只被引用而不改變其值,則這時用靜態區域性變數比較方便,以免每次呼叫時重新賦值。 但是應該看到,用靜態儲存要多佔記憶體,而且降低了程式的可讀性,當呼叫次數多時往往弄不清靜態區域性變數的當前值是什麼。因此,如不必要,不要多用靜態區域性變數。

用register宣告暫存器變數

一般情況下,變數的值是存放在記憶體中的。當程式中用到哪一個變數的值時,由控制器發出指令將記憶體中該變數的值送到CPU中的運算器。經過運算器進行運算,如果需要存數,再從運算器將資料送到記憶體存放。如圖4.15所示。


圖 4.15

為提高執行效率,C++允許將區域性變數的值放在CPU中的暫存器中,需要用時直接從暫存器取出參加運算,不必再到記憶體中去存取。這種變數叫做暫存器變數,用關鍵字register作宣告。例如,可以將例4.14中的fac函式改寫如下:

  1. int fac(int n)
  2. {
  3. register int i,f=1; //定義i和f是暫存器變數
  4. for(i=1;i<=n;i++) f=f*i;
  5. return f;
  6. }

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

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

用extern宣告外部變數

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

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

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

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

  1. #include <iostream>
  2. using namespace std;
  3. int max(int,int); //函式宣告
  4. void main( )
  5. {
  6. extern int a,b;//對全域性變數a,b作提前引用宣告
  7. cout<<max(a,b)<<endl;
  8. }
  9. int a=15,b=-7;//定義全域性變數a,b
  10. int max(int x,int y)
  11. {
  12. int z;
  13. z=x>y?x:y;
  14. return z;
  15. }

執行結果如下:
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()
{
cout<<a<<“,”<<b<<end!;
return 0;
}

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宣告靜態外部變數

有時在程式設計中希望某些外部變數只限於被本檔案引用,而不能被其他檔案引用。這時可以在定義外部變數時加一個static宣告。例如:
file1.cpp
static int a=3;
int main ( )
{

}

file2.cpp
extern int a;
int fun (int n)
{

a=a*n;

}

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

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

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

相關推薦

C/C++中的變數儲存類別以及記憶體分配

本文也是總結了網上一些大神們的部落格(寫得太牛逼了),然後結合自己看書的一些內容。參考:                   http://hi.baidu.com/lcplj123/item/e984cd0f921e39c12e4c6baa http://www.eefo

變數宣告和定義的區別||變數儲存類別小結(C程式設計中的內容)

我們在程式設計中,時時刻刻都用到變數的定義和變數的宣告,可有些時候我們對這個概念不是很清楚,知道它是怎麼用,但卻不知是怎麼一會事,下面我就簡單的把他們的區別介紹如下: 變數的宣告有兩種情況:

理解C++變數儲存模型

在理解程式記憶體一文中我們介紹了普通程式執行時在記憶體中的佈局,下面我們專門針對C++原始碼以WinDbg為工具分析下C++程式的變數儲存模型, 要理解下面的知識,請先看懂理解程式記憶體一文。下面我們嘗試分析C++變數的儲存模型, 我們的測試程式非常簡單:#include <iostream

c++ 變數儲存型別

extern 儲存型別 : 只宣告而不定義變數,變數的宣告只是告訴編輯器變數的名稱和資料型別;變數的定義是給變數分配儲存區域;優點就是可以在多個檔案裡面共享一個全域性變數, static 儲存型別: static指的是靜態變數(又叫永續性變數);靜態變數分為兩種,第一種是區

C語言儲存類別

1.作用域 在C語言中,變數的作用域可以是塊作用域、函式作用域、函式原型作用域或檔案作用域 塊作用域 塊是指用一堆花括號括起來的程式碼區域,定義在塊中的變數具有塊作用域,塊作用域變數的可見範圍是

區域性變數儲存類別

1.自動變數(auto) int f(int a) { auto int a,b; } auto 可以省略 int b,c=3;等價於 auto int b,c=3; 2.靜態區域性變數(static) #include< s

C語言儲存類別和連結

目錄 C語言儲存類別和連結 儲存類別 儲存期 五種儲存類別 C語言儲存類別和連結 ​ 最近詳細的複習C語言,看到儲存類別的時候總感覺一些概念模糊不清,現在認真的

C語言中區域性變數和全域性變數變數儲存類別(static,extern,auto,register)

C語言中區域性變數和全域性變數變數的儲存類別(static,extern,auto,register) 1----區域性變數和全域性變數 在討論函式的形參變數時曾經提到,形參變數只在被呼叫期間才分配記憶體單元,呼叫結束立即釋放。這一點表明形參變數只有在函式內才是有效的,離開該函式就不能再使用了。

C++變數儲存類別

動態儲存方式與靜態儲存方式 我們已經瞭解了變數的作用域。作用域是從空間的角度來分析的,分為全域性變數和區域性變數。 變數還有另一種屬性——儲存期(storage duration,也稱生命期)。儲存期是指變數在記憶體中的存在期間。這是從變數值存在的時間角度來分析的。儲存期可以分為靜態儲存期(static s

C++變數儲存類別與作用域

總結一下C++中變數的儲存類別以及變數的作用域。 (1)標示符的儲存類別決定了標示符在記憶體中存在的時間(我們可以理解標示符就是確定一個變數的符號,也就是我們所說的變數名) 二:儲存類別 (1)靜態儲存類別:靜態存數類別變數(我們簡稱靜態變數),從程式的開始處就存在,其

c/c++ 中變數儲存類別

1. 變數分類 從變數的作用域 全域性變數 在函式外部定義的變數被稱作外部變數或全域性變數。 區域性變數 在函式內部定義的變數,只在本函式內部有效。 從變數的儲存時間(生存週期) 靜態儲存方式 程式執行期間固定分配的儲存空間。 動態儲存方式 程式

C++學習之:變數儲存類別

在c++中,每個變數有兩個屬性:型別:變數所儲存的資料型別(如int、double、char);儲存型別:變數所儲存的區域(atuo、register、extern、static)變數的作用域決定了變數的有效範圍。變數的儲存類別決定了變數的生存期限。在計算機中,記憶體被分成不

C語言-變數儲存類別(auto, static, register, extern)

任何一個變數和函式都有兩個屬性,1、資料型別(我們已經熟知) 2、資料的儲存類別 有2種儲存方式,有4種儲存類別 auto自動變數 一般來說auto可以省略,1、函式的形參 2、在函式中定義的區域性變數(包括在複合語句中定義的區域性變數)都是自動變數auto。上述2種自動變

C語言中儲存類別、連結與記憶體管理

  第12章 儲存類別、連結和記憶體管理 通過記憶體管理系統指定變數的作用域和生命週期,實現對程式的控制。合理使用記憶體是程式設計的一個要點。 12.1 儲存類別 C提供了多種不同的模型和儲存類別,在記憶體中儲存資料。 被儲存的每一個值都佔用一定的實體記憶體;C語言把這樣一塊記憶體稱為物件

C語言的儲存類別和動態記憶體分配

儲存類別分三大類: 靜態儲存類別 自動儲存類別 動態分配記憶體   變數、物件--->記憶體管理 記憶體考慮效率(時間更短、空間更小) 作用域 連結、---->空間 儲存器   ----->時間   其實儲存類別(時間、空間)和資料

變數儲存類別

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

關於變數儲存類別的理解。

         作為在嵌入式底層搬磚兩年的一個embeder,最近兩度被xxx提問關於關鍵字的用法提問住了,於是回來馬上對嵌入式C中的關鍵字做一個總結和框圖化整理。          C語言中關鍵字:auto、extern、static、 register、const、v

C++ 程式碼和變數儲存位置

棧:程式自動分配,編譯器在需要的時候分配,不需要的時候自動清除的變數儲存區 堆:程式設計師手動分配由new分配的記憶體,需要自己在程式裡面手動釋放 常量儲存區:存放的是常量,不允許修改,編譯時分配,程

c語言一個字元變數儲存多個字元

#include<stdio.h> int main() { char s; char a = 'a'; scanf("%s",&s); printf("input word is:%s, %c\n",&a

C語言中變數儲存型別有哪些?

    變數的儲存型別是C語言的重要組成部分,也是C語言學習的基礎。那C語言中變數的儲存型別有哪幾種呢?在程式設計過程中又該怎樣運用呢?就這一問題,我今天給大家介紹一下!總的來說,C語言中變數的儲存型別可以分為四種,他們分別是自動變數、靜態變數、外部變數和暫存器變數這四種,