C Primer Plus 第 12 章 存儲類別口柳,鏈接和內(nèi)存管理

關(guān)鍵字:auto, extern有滑, static跃闹,const
函數(shù):malloc(),free()
主要內(nèi)容:變量的作用域(可見的范圍)和生命周期(它存在多長時間)


存儲類別總結(jié)

C語言中毛好,有5種存儲類別(不包括線程)望艺。下面先定義,再慢慢解釋具體的概念肌访。

自動:

無特殊說明或者帶auto說明符聲明的變量找默,自動存儲期,塊作用域吼驶,無鏈接惩激。如果未初始化店煞,其值未定義。

靜態(tài)风钻,外部鏈接:

在所有函數(shù)外部并且 沒有 使用 static 來聲明變量是靜態(tài)的顷蟀,靜態(tài)存儲期,文件作用域骡技,外部鏈接鸣个。只能被編譯器初始化一次。如果未初始化布朦,其值默認為0囤萤。外部鏈接的意思是,其他 .c 文件 可以 通過extern來調(diào)用該文件中定義的此變量是趴。

靜態(tài)阁将,內(nèi)部鏈接:

在所有函數(shù)外部并且 使用 static 來聲明變量是靜態(tài)的,靜態(tài)存儲期右遭,文件作用域做盅,內(nèi)部鏈接。只能被編譯器初始化一次窘哈。如果未初始化吹榴,其值默認為0。外部鏈接的意思是滚婉,其他 .c 文件 不可以 通過extern來調(diào)用該文件中定義的此變量图筹。

靜態(tài),無鏈接:

在某塊中被 static 說明符聲明让腹,靜態(tài)存儲期远剩,塊作用域,無鏈接骇窍。只能被編譯器初始化一次瓜晤。如果未初始化,其值默認為0腹纳。

寄存器變量:

未使用過痢掠,暫不介紹。


概念解釋

存儲期

存儲期表示一個變量在內(nèi)存中存在了多長時間嘲恍。用作用域和鏈接去描述標識符(諸如static, const, extern)足画。

作用域和鏈接

作用域和鏈接可以表明,這個變量可以被程序的哪個塊佃牛,哪個函數(shù)淹辞,哪個文件所調(diào)用。


概念詳解

自動:

學(xué)習(xí)編程期間俘侠,我們見到的大多數(shù)變量都是自動變量象缀。它在 塊中(任意一對花括號中間)被定義彬向,并且無static聲明。自動變量只在被定義的塊中有效攻冷。它在程序執(zhí)行到塊中聲明語句時被創(chuàng)建娃胆, 它在函數(shù)進入塊時被分配內(nèi)存,在該塊結(jié)束時被自動釋放等曼。

靜態(tài):

static變量恐怕是很多初學(xué)者的FAQ里烦,其實了解后就會發(fā)現(xiàn)它的定義非常簡單。那就是static的變量禁谦,在程序被載入到程序結(jié)束期間都存在胁黑,當程序結(jié)束時被自動釋放(即使該static變量是在某塊中被初始化,它占用的內(nèi)存不會在塊結(jié)束時被釋放州泊。)

外部丧蘸,內(nèi)部,無鏈接:

這三個概念其實也非常簡單遥皂。當一個變量像我們include stdio.h 一樣力喷,定義在所有函數(shù)外部,那么這個變量就是有鏈接的演训。如果他同時被static聲明弟孟,那么它是內(nèi)部鏈接,內(nèi)部鏈接不能被其他 .c 通過extern訪問样悟,我們可以理解成只在該文件內(nèi)的 “全局變量”拂募。相反,如果沒有static聲明窟她,那么該文件可以被其他 .c文件通過extern訪問陈症,它是所有文件都能用的“全局變量”。而靜態(tài)無鏈接變量震糖,這種儲存類型的文件只能在被定義的塊中被訪問录肯,換句話說,此變量的作用域是定義它的塊试伙。


存儲類別異同和注意事項

  • 自動變量在被初始化時嘁信,它的值會繼承這塊內(nèi)存上一次儲存的值(如果存在)于样,總之你別期待著它自動變成 0 疏叨。但是如果我們定義 static 變量時,沒有給它初始化穿剖,那么它的值默認0 蚤蔓。如果變量是數(shù)組名,那么所有數(shù)組成員都為0 糊余。

  • 一般我們在創(chuàng)建自動變量時秀又,不需要加上 auto单寂,一般加auto是強調(diào),我需要創(chuàng)建一個和 static 變量同名的變量名吐辙,來特指宣决。個人建議沒事閑的別建同名的變量。

  • 塊作用域static變量舉例昏苏,比如for 循環(huán)中的 static 聲明尊沸,例如:

for (int i = 0; i < 2; i++) {


        int x = 1;

        static int y = 1;
        
        printf("x is %d, y is %d", ++x, ++y);
    }
可以設(shè)想一下,這個函數(shù)運行的時候printf都會輸出什么贤惯,
答案是洼专,x是自動變量,自動變量在塊結(jié)束時都會被釋放孵构。
每次進入for循環(huán)塊屁商,x都會被重新聲明為1,所以printf的第一項永遠為2颈墅,
但是static int y = 1這條語句在程序開始時就被分配內(nèi)存蜡镶。

static int y = 1; 這條聲明實際上不是for的一部分。
如果開啟調(diào)試模式恤筛,你會發(fā)現(xiàn)帽哑,程序似乎   跳過  了這條聲明。
因為靜態(tài)變量和外部變量在程序被載入時內(nèi)存已執(zhí)行完畢叹俏。
把這條語句放在for里面是為了告訴編輯器妻枕,   只有這個for循環(huán)  才能  “看到”  該變量。
**這條聲明未在運行時執(zhí)行粘驰。**
  • 什么時候需要用到extern屡谐?

    • 如果一個變量定義在另一個文件內(nèi),而我們要在自己的文件內(nèi)使用它蝌数,那么必須使用 extern 來聲明愕掏,我使用了其他文件中的 靜態(tài)外部鏈接 變量。

    • 聲明了外部變量顶伞,可以在函數(shù)中使用extern來強調(diào)饵撑,我接下來要用的變量是外部變量。

int num;

int arr[10];

int main(void){

        extern int num;

        extern int arr[];

}

這里其實完全可以省略 extern int num; extern int arr[]; 這兩條代碼唆貌,
它們僅僅是為了強調(diào)這兩個變量是全局變量滑潘。
但是要刪除的話就全刪除掉, 如果只刪除了 extern锨咙,那么實際上你是建立了兩個同名的自動變量语卤。
  • 我們正常創(chuàng)建的函數(shù),都是外部定義的,所以這些函數(shù)都可以被其他 .c中使用 extern調(diào)用粹舵。同時函數(shù)也可以被靜態(tài)定義钮孵,靜態(tài)函數(shù)只能在該文件內(nèi)使用。

  • 外部變量只能初始化一次眼滤,且必須在定義變量時進行巴席,并且初始化只能使用常量表達式。


malloc和free

malloc函數(shù)接收一個參數(shù)诅需,那就是大小情妖,返回一個參數(shù),代表生成內(nèi)存的首字節(jié)地址诱担。把這個地址賦值給一個指針變量毡证,指針就可以訪問這個內(nèi)存了。

malloc生成的內(nèi)存是void類型的蔫仙,所以在使用的時候盡量使用強制類型轉(zhuǎn)換料睛。

int *res = (int *)malloc(sizeof(int) * ASize); // (刷過leetcode懂得都懂。摇邦。恤煞。)

free函數(shù)的參數(shù),是之前malloc返回的地址施籍。既然是地址居扒,我們就沒必要非得free當時malloc賦值給的那個指針,只要你free參數(shù)的指針丑慎,指向的是那個地址就行喜喂。

老生常談的問題,為什么一定要free竿裂。假設(shè)你在for循環(huán)中malloc并指向一個自動變量指針玉吁,如果沒有在for循環(huán)中free,那么這個自動變量在每次塊結(jié)束的時候就被釋放腻异,相當于你就再也找不到這個地址了进副,想釋放都釋放不了。那么循環(huán)1萬次悔常,每次都無法釋放影斑,讓冗余的數(shù)據(jù)占據(jù)內(nèi)存,之后很可能就堆棧溢出了机打。這類問題就叫內(nèi)存泄漏(Memory Leak)矫户。


存儲類別和動態(tài)內(nèi)存分配

這個部分詳細說的話,可以再寫一篇博客了姐帚。所以這里只說結(jié)論吏垮。

Malloc生成的變量障涯,存放在堆罐旗。

自動變量膳汪,都存放在上。

堆和棧加起來九秀,叫動態(tài)存儲區(qū)遗嗽,這個地方的內(nèi)存一會變大一會變小,所以是動態(tài)的鼓蜒。

靜態(tài) 痹换、常量、全局變量都弹,存儲在靜態(tài)存儲區(qū)娇豫,也叫全局存儲區(qū)。


堆和棧的五大區(qū)別:

(我在百度上一搜畅厢,反而是一個廣告網(wǎng)站里總結(jié)的挺好冯痢,就不附上鏈接了怕廣告嚇到你。框杜。浦楣。)

  1. 申請方式不同。棧由系統(tǒng)自動分配咪辱,堆是程序員認為申請開辟振劳。

  2. 申請大小不容。棧獲得的空間小油狂,堆獲得的空間大历恐。

  3. 申請效率不同。 棧由系統(tǒng)自動分配专筷,速度快夹供,堆速度較慢。

  4. 存儲內(nèi)容不同仁堪。 棧在函數(shù)調(diào)用時哮洽,函數(shù)調(diào)用語句的下一條可執(zhí)行語句的地址第一個進棧,然后函數(shù)的各個參數(shù)進棧弦聂,靜態(tài)變量不入棧鸟辅。堆一般在頭部用一個字節(jié)存放堆的大小,堆中內(nèi)容人為安排莺葫。

  5. 底層不同匪凉。 棧是連續(xù)的空間,堆是不連續(xù)的空間捺檬。


const類型限定符使用

類型限定符一共有三種: const再层, volatile,restrict. 由于 const 最常用并且我還沒有用到過其他兩個限定符,就先專門總結(jié)一下const吧聂受。

const 的目的是讓被定義的變量無法被改變蒿秦,聽起來挺簡單的,不過很多使用的時候也會有一些小坑蛋济。


const聲明指針時候的位置


const int *p;

int * const p;

const int * const p;

最上面兩條代碼是有區(qū)別的棍鳖。關(guān)注點在 const 是在 * 左邊還是右邊。

第一條代碼聲明了一個 int 型指針變量碗旅,p解引用(*p的值)是不能被改變的渡处。但是,p可以指向其他的值祟辟。

第二條代碼聲明了一個固定地址的p医瘫,即該指針只能指向這個地址,但是這個地址上面的值是可以被改變的旧困。

第三條代碼當然是全部都固定住不能改變醇份。

const in *p = NULL;

*p = 5;    // 這里會報錯: Read-only variable is not assignable

雖然解引用(*p的值)是不能被改變的。但是叮喳,p可以指向其他的變量被芳,解引用獲得其他的值。

int main(void)

{   

    int a = 5;

    const int *p = NULL;

    p = &a;

    printf("%d", *p);

}

對全局數(shù)據(jù)使用const

外部鏈接的全局變量可能被其他文件 extern調(diào)用馍悟,所以為了防止他們被意外更改畔濒,還是加上const較好。

同時如果為了省事锣咒,我們可以把 const double PI = 3.14 這種語句寫在頭文件里面侵状,然后在其他 .c 文件中 extern就好了。

但是這里也有坑毅整,那就是寫在 頭文件 中的全局變量聲明趣兄,最好加上 static ,因為如果不加悼嫉,那么每個 include 了這個 頭文件的 .c文件艇潭,都會多出一句這個代碼 : const double PI = 3.14

而且這種聲明都是外部鏈接啊,那到時候萬一有的文件沒有 include 這個 頭文件戏蔑,而是選擇 extern 這個變量蹋凝, 那么編譯器怎么知道它到底想要的是哪個 PI?

其實C標準是不允許這么做的总棵,所以寫在頭文件里面的東西鳍寂,最好還是加上 static,要不然容易出問題情龄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末迄汛,一起剝皮案震驚了整個濱河市捍壤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鞍爱,老刑警劉巖鹃觉,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異硬霍,居然都是意外死亡帜慢,警方通過查閱死者的電腦和手機笼裳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門唯卖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人躬柬,你說我怎么就攤上這事拜轨。” “怎么了允青?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵橄碾,是天一觀的道長。 經(jīng)常有香客問我颠锉,道長法牲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任琼掠,我火速辦了婚禮拒垃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瓷蛙。我一直安慰自己悼瓮,他們只是感情好,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布艰猬。 她就那樣靜靜地躺著横堡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪冠桃。 梳的紋絲不亂的頭發(fā)上命贴,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天,我揣著相機與錄音食听,去河邊找鬼胸蛛。 笑死,一個胖子當著我的面吹牛碳蛋,可吹牛的內(nèi)容都是我干的胚泌。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼肃弟,長吁一口氣:“原來是場噩夢啊……” “哼玷室!你這毒婦竟也來了零蓉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤穷缤,失蹤者是張志新(化名)和其女友劉穎敌蜂,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體津肛,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡章喉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了身坐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秸脱。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖部蛇,靈堂內(nèi)的尸體忽然破棺而出摊唇,到底是詐尸還是另有隱情,我是刑警寧澤涯鲁,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布巷查,位于F島的核電站,受9級特大地震影響抹腿,放射性物質(zhì)發(fā)生泄漏岛请。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一警绩、第九天 我趴在偏房一處隱蔽的房頂上張望崇败。 院中可真熱鬧,春花似錦房蝉、人聲如沸僚匆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咧擂。三九已至,卻和暖如春檀蹋,著一層夾襖步出監(jiān)牢的瞬間松申,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人盒件。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像皇筛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子坠七,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359