—————————————————————————————————————————————————————————————————————————————
只有不斷的學習,不斷的進步,才能不被替代。
只有你的不可替代性才決定你的價值。
-----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(對數值型變數)或Null 字元(對字元變數)。而對自動變數來說,如果不賦初值則它的值是一個不確定的值。
register變數
為了提高效率,C語言允許將局部變數得值放在CPU中的寄存器中,這種變數叫“寄存器變數”,用關鍵字register作聲明。
說明:
1) 只有局部自動變數和形式參數可以作為寄存器變數;
2)一個電腦系統中的寄存器數目有限,不能定義任意多個寄存器變數;
3)局部靜態變數不能定義為寄存器變數。
用extern聲明外部變數
外部變數(即全域變數)是在函數的外部定義的,它的範圍為從變數定義處開始,到本程式檔案的末尾。如果外部變數不在檔案的開頭定義,其有效作用範圍只限於定義處到檔案終了。如果在定義點之前的函數想引用該外部變數,則應該在引用之前用關鍵字extern對該變數作“外部變數聲明”。表示該變數是一個已經定義的外部變數。有了此聲明,就可以從“聲明”處起,合法地使用該外部變數。
extern 例子:
在 main 函數體外定義的變數,A 、B(外部變數:它的範圍為從變數定義處開始,到本程式檔案的末尾。)。想要在main中引用必須加關鍵字:extern 。
第三部分:C語言的堆與棧
和棧的第一個區別就是申請方式不同:棧(英文名稱是stack)是系統自動分配空間的,例如我們定義一個 char a;系統會自動在棧上為其開闢空間。而堆(英文名稱是heap)則是程式員根據需要自己申請的空間,例如malloc(10);開闢十個位元組的空間。由於棧上的空間是自動分配自動回收的,所以棧上的資料的生存周期只是在函數的運行過程中,運行後就釋放掉,不可以再訪問。而堆上的資料只要程式員不釋放空間,就一直可以訪問到,不過缺點是一旦忘記釋放會造成記憶體泄露。