1. 程式人生 > >C++ 函式作用域

C++ 函式作用域

變數作用域

區域性作用域、全域性作用域、檔案作用域

區域性變數:也稱內部變數,宣告在函式內(包括main函式),作用域開始於變數宣告之處,結束於函式或塊結束處;

全域性變數:也稱外部變數,宣告在函式外,作用域一般是整個程式原始檔,作用域最廣,甚至可以作用於組成該程式的所有原始檔(比如,將多個獨立編譯的原始檔連結成一個程式時,在某個原始檔中宣告的全域性變數,在與該原始檔相連結的其他原始檔中也可以使用,但使用前必須進行extern全域性宣告。這樣,多個原始檔中的所有函式都能使用全域性變數,在一個函式中改變了一個全域性變數的值,就會作用到使用該全域性變數的其他所有函式,相當於各函式之間有了一條直接傳遞資料的通道。當然這也破壞了獨立性)

檔案作用域:在函式外部宣告的變數只在當前檔案範圍內(包括檔案內所有定義的函式)可用,在其他檔案不可用。要使變數具有檔案作用域,必須在變數的宣告前加static關鍵字。當多個原始檔連結成一個程式時,static可以避免一個檔案中的全域性變數與其它檔案中的變數同名而發生衝突。

在同一作用域內的變數不能同名,但在不同作用域內的變數可用同名,在本作用域會覆蓋/遮蔽其它作用域的同名變數。(我的地頭我做主)

1. static全域性變數和普通全域性變數區別?

在全域性變數宣告前加static -> static全域性變數,全域性變數本身是靜態儲存方式,靜態全域性變數也是靜態儲存方式,在儲存方式上無區別。

主要區別在於非靜態全域性變數的作用於是整個源程式(由多個源程式組成的話,在各個原始檔中都有效);靜態全域性變數限制了作用域,只在定義該變數的原始檔中有效(全域性作用域->檔案作用域),可避免在其他檔案中引起錯誤。static變數只初始化一次,下一次依照上一次的值

2. static區域性變數和普通區域性變數區別?

在區域性變數宣告前加static -> 靜態區域性變數,儲存方式改變了,區域性變數是動態儲存,靜態區域性變數是靜態儲存方式,也就是改變了它的生存期,由函式內部或者塊內部變為檔案作用域,雖然並不是真正的“檔案作用域”,宣告在函式內,但是在函式外部無法訪問,作用應該只是為了避免重名衝突。

PS: 靜態區域性變數擴大了局部變數的生存期,靜態全域性變數縮小了全域性變數的作用域

3. static函式與普通函式區別?

靜態函式與普通函式作用域不同,僅在本檔案。內部函式:只在當前原始檔中宣告和定義的函式稱為內部函式(static);對於可在當前原始檔以外使用的函式,應該在標頭檔案中說明,或者進行extern全域性宣告。static函式在記憶體中只有一份,普通函式在每個被呼叫中維持一份拷貝。

 函式的儲存型別

分為內部函式(static) 和外部函式(extern)兩類。內部函式:只能被同一個原始檔中的函式所呼叫;外部函式:可以被其他原始檔中的函式所呼叫。

沒有定義儲存型別的函式預設extern。

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

變數的儲存型別

任何變數都有資料型別和儲存型別兩種屬性。完整的變數宣告,除了宣告代表變數運算屬性的資料型別,有時還需要宣告代表變數儲存方式的儲存型別。

除了分配記憶體空間大小,還要分配不同型別的記憶體空間。

變數的儲存型別決定了C++編譯器為變數分配記憶體的方式,決定了變數的生存期

準確來說,變數的生存期和作用域是從不同角度分析變數的屬性。

變數的作用域:空間範圍,從程式碼空間角度,哪段程式碼看得見,哪段程式碼看不見。關鍵是“可見性”和“可用性”。

變數的生存期:從程式碼的執行時間角度考慮,是指在程式執行的過程中變數從建立到被撤銷的一段時間,即變數的生命週期。當變數被分配了記憶體空間,就處於生存期;當所佔的記憶體空間被釋放,這個變數就結束了生存期。關鍵是“存活狀態”。

最明顯的就是靜態區域性變數。

// 靜態區域性變數使用

void fun()

{

static int a;//靜態變數a是區域性變數,但具有全域性變數的生存期

a++;

cout << "a = "<< a<<endl;

}

int main()

{

for(int i = 0; i < 2; i++)//靜態變數a不在作用域內

fun();

}

結果是

a = 1

a = 2

分析:宣告靜態變數時如果沒有初始化,則“初始化”值為0,靜態全域性變數的初始化是在執行main之前完畢,靜態區域性變數的初始化是在程式執行後第一次執行該變數的宣告語句時進行。

下例:在MyFunc()中第一個宣告的區域性變數(x=1)在隨後的語句塊中雖然處於生存期(因為宣告和定義它的MyFunc()函式塊還沒有結束),但不在作用域,因為被語句塊內同名的區域性變數x(2)遮蔽(/覆蓋)了,但是一旦語句塊結束,x(2)的生存期也就結束了,在MyFunc()內只有x = 1生存。區域性變數x(2),y(2)雖然在語句塊內生存,但進入函式FuncA()後也是不可用的。

void MyFunc(){

int x = 1;

{

int x(2),y(2);//變數" x = 1"失去作用域

cout << "x = "<<x<<"\n";

FuncA(); //變數X(2),Y(2)進入函式後失去作用域

}

}

記憶體的分配方式:自動分配,靜態分配,動態分配,所佔記憶體區域和變數型別如下:



靜態分配
:編譯時就分配了記憶體地址,執行時變數就佔用記憶體,知道程式結束時變數才釋放記憶體。 

動態分配:利用堆(heap)這個記憶體塊為變數分配記憶體,堆使用了除棧、靜態儲存區之外的自由儲存空間。是一種完全由程式自身控制記憶體分配的方式(控制包括開闢空間new、釋放空間delete

對於非動態記憶體分配方式的變數,決定變數採用哪種記憶體分配方式,是由宣告變數時指定儲存型別和宣告語句在程式中的位置決定的。

C++變數的儲存類:

auto, register, extern, static

宣告時可指定:

<儲存型別>  <資料型別>  <變數名列表>;

auto int a;

static float b,c;

registerauto宣告區域性變數:register儲存在暫存器,auto儲存在棧

extern宣告全域性變數,static宣告全域性變數和區域性變數

externstatic都在靜態儲存區。

沒有指定儲存型別,預設如下:

區域性變數:auto

全域性變數:extern

全域性變數:定義性宣告和引用性宣告

定義性宣告定義變數,分配記憶體空間。只能在函式外部,一般不加extern

引用性宣告表示變數已經在程式原始檔中其他地方進行過定義性宣告(已分配空間)。可以放在函式外,也可以放在函式內,要加extern,一般不能對變數初始化,除非定義性宣告沒有初始化。

程式有多個原始檔組成,如果每個檔案都要使用同一個全域性變數,在每個檔案中都要進行全域性變數的宣告,但如果是定義性宣告,編譯每個原始檔不會出錯,連結它們則出現重複定義錯誤。所以方法是在一個原始檔中進行定義性宣告,其它檔案引用性宣告。