1. 程式人生 > >C語言全域性變數和區域性變數總結

C語言全域性變數和區域性變數總結

—————————————————————————————————————————————————————————————————————————————

只有不斷的學習,不斷的進步,才能不被替代!

只有你的不可替代性才決定你的價值!

-----2016年11月18日

—————————————————————————————————————————————————————————————————————————————

第一部分問題:

今天一個小夥伴問我一個問題,如圖程式1:


咋一看沒有問題啊,後來想想確實有問題,這個c=a+a;似乎是語句,必須在函式體內才能執行,後來就看到這麼一句話:

賦值語句需要有函式執行,c語言最基本的執行體是函式,你可以初始化,但不能在函式體外賦值。

在VC++中,確實出錯,指標的地方出錯,錯誤提示:


錯誤說的是:初始化必須是一個常量。

然後我就去掉運算的c。如圖程式2:


顯示可以正常執行的。然後就比較鬱悶,就問了QQ好友(矩陣)。正確答案如下:

函式體外只能進行初始化,不能進行賦值運算。如圖程式3:


提示的錯誤是:變數a被重複賦初值。

其實正確的理解就是:函式體外只能進行初始化,不能進行賦值運算。為什麼第二個程式可以執行?

因為,C語言執行過程中,對程式碼進行了優化,把程式2中的 int a; a=10;  優化為一句話:int a=10;這就是初始化。所以程式2是正確的,程式3中,初始化過程中:int a=10;int a=17;肯定就出錯了。重複初始化。程式1中,語句必須在函式體內執行,函式體外只能進行初始化。

第二部分全域性變數與區域性變數

定義:

區域性變數(Local Variable):定義在函式體內部的變數,作用域僅限於函式體內部。離開函式體就會無效。再呼叫就是出錯。

全域性變數(Global Variable):定義:所有的函式外部定義的變數,它的作用域是整個程式,也就是所有的原始檔,包括.c和.h檔案。

全域性變數的例子,如圖程式4:

提示的錯誤是 變數 x 沒有定義,原因是:

C語言程式碼是從前往後依次執行的,由於 x 定義在函式 func1() 之後,所以在 func1() 內無效;修改程式如下,程式5:


可以看出,輸出正確的答案,所以全域性變數必須定義在我們需要用它的函式體之前。

然後,在看下區域性變數:


注意事項:

①在main函式中定義的變數也是區域性變數,只能在main函式中使用;同時,main函式中也不能使用其他函式中定義的變數。main函式也是一個函式,與其它函式地位平等。

②形參變數、在函式體內定義的變數都是區域性變數,實參給形參傳值的過程也就是給區域性變數賦值的過程。

③可以在不同的函式中使用相同的變數名,它們表示不同的資料,分配不同的記憶體,互補干擾,也不會發生混亂。

④在語句塊(由一對{}包含的若干條語句)中也可以定義變數,它的作用域只限於當前的語句塊。

一道綜合練習題:


①先呼叫fun1(),在fun1()中,有區域性變數n,所以輸出的結果是  n:20;

②對於fun2(),使用了形參,形參的作用範圍也是整個函式內(實參給形參傳值的過程也就是給區域性變數賦值的過程),所以輸出的結果是  n:30;

③對於fun3(),沒有區域性變數,所以全域性變數定義的 n 對所有的函式都可見。所以輸出的結果是  n:10;

④根據區域性變數注意事項第四條。所以輸出的結果是  n:40;

⑤3C語言規定,只能從小的作用域向大的作用域中去尋找變數,而不能反過來,使用更小的作用域中的變數。對於 main() 函式,即使程式碼塊中的 n 離輸出語句更近,但它仍然會使用 main() 函式開頭定義的 n,所以輸出結果是 30。

所以結果是:


第三部分記憶體的分割槽和變數的儲存

記憶體中供使用者使用的儲存空間分為三部分:程式區  、靜態儲存區、動態儲存區。

變數的分類:

①從空間上分配:從變數的作用域可以分成:區域性變數和全域性變數。

②從變數的存在時間(生存週期)可以分成:靜態儲存和動態儲存。

靜態儲存:程式在執行期間分配固定的儲存方式。

動態儲存:程式在執行期間根據需要動態的分配儲存空間。

全域性變數全部儲存在靜態儲存區。在程式開始執行過程中給全域性變數分配空間,程式執行完畢就釋放空間。程式執行過程中固定的分配空間,而不需要動態進行分配是釋放。

動態儲存區主要存放以下資料:函式的形參、自動變數(沒有加static的區域性變數)、函式呼叫的現場現場保護和返回值。

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

C語言中每個變數有兩個屬性:第一資料型別;第二儲存屬性。

auto 變數:

函式中的區域性變數,如果不專門的宣告為 static儲存,都是動態分配儲存空間。資料儲存在動態儲存區內。函式中的形參和函式中的變數都屬於此類,呼叫該函式時候系統自動的分配空間,在函式結束的時候,釋放該空間。這些區域性變數被稱為自動變數。自動變數用 auto關鍵字宣告(可以省略auto )。

static 變數:

有時候希望我們呼叫的函式在釋放的時候不消失能保留原值,這就需要定義為靜態區域性變數。用關鍵字 static宣告。
看一段程式:


對靜態區域性變數的說明:
1)靜態區域性變數屬於靜態儲存類別,在靜態儲存區內分配儲存單元。在程式整個執行期間都不釋放。而自動變數(即動態區域性變數)屬於動態儲存類別,佔動態儲存空間,函式呼叫結束後即釋放。
2)靜態區域性變數在編譯時賦初值,即只賦初值一次;而對自動變數賦初值是在函式呼叫時進行,每呼叫一次函式重新給一次初值,相當於執行一次賦值語句。
3)如果在定義區域性變數時不賦初值的話,則對靜態區域性變數來說,編譯時自動賦初值0(對數值型變數)或空字元(對字元變數)。而對自動變數來說,如果不賦初值則它的值是一個不確定的值。

register變數
為了提高效率,C語言允許將區域性變數得值放在CPU中的暫存器中,這種變數叫“暫存器變數”,用關鍵字register作宣告。

說明:
1) 只有區域性自動變數和形式引數可以作為暫存器變數;
2)一個計算機系統中的暫存器數目有限,不能定義任意多個暫存器變數;
3)區域性靜態變數不能定義為暫存器變數。

用extern宣告外部變數
外部變數(即全域性變數)是在函式的外部定義的,它的作用域為從變數定義處開始,到本程式檔案的末尾。如果外部變數不在檔案的開頭定義,其有效的作用範圍只限於定義處到檔案終了。如果在定義點之前的函式想引用該外部變數,則應該在引用之前用關鍵字extern對該變數作“外部變數宣告”。表示該變數是一個已經定義的外部變數。有了此宣告,就可以從“宣告”處起,合法地使用該外部變數。

extern 例子:


在 main 函式體外定義的變數,A 、B(外部變數:它的作用域為從變數定義處開始,到本程式檔案的末尾。)。想要在main中引用必須加關鍵字:extern 。

第三部分:C語言的堆與棧

和棧的第一個區別就是申請方式不同:棧(英文名稱是stack)是系統自動分配空間的,例如我們定義一個 char a;系統會自動在棧上為其開闢空間。而堆(英文名稱是heap)則是程式設計師根據需要自己申請的空間,例如malloc(10);開闢十個位元組的空間。由於棧上的空間是自動分配自動回收的,所以棧上的資料的生存週期只是在函式的執行過程中,執行後就釋放掉,不可以再訪問。而堆上的資料只要程式設計師不釋放空間,就一直可以訪問到,不過缺點是一旦忘記釋放會造成記憶體洩露。