深入C語言之記憶體問題

2021-05-22 00:49:08 字數 2112 閱讀 5029

最近瘋狂學習c語言當中,看到有啟蒙文章,心中大喜,隨複製。

記憶體,c語言中出現詭異bug的兩大"源泉"之一。即使是久經沙場的老手,也有時也難免落入陷阱。本文將涉足這個雷區,一**竟。本人菜鳥乙隻,屬於初探,不敢深挖。

記憶體分為哪些段?

一般來說,c語言中記憶體分為:棧(stack)、堆(heap)、全域性變數區、文字常量區、程式**區。

棧:自動變數、函式引數以及每次函式呼叫時所需儲存的資訊放在此段中。如函式呼叫時要儲存返回位址等。棧是由編譯器自動分配釋放管理,無需我們手工控制,它的生長方向是從上向下分配(即向著記憶體位址減小的方向增長)。正是通過棧的特性,c函式可以實現遞迴呼叫。

堆:就是那些由malloc/calloc分配的記憶體塊,它們的釋放編譯器不去管,由我們的手動去控制,一般乙個 malloc/calloc就要對應乙個free。堆的生長方向是向上分配(向著記憶體位址增加的方向)。一般來講在32位系統下,堆記憶體可以達到4g的空 間,從這個角度來看堆記憶體幾乎是沒有什麼限制的。但是對於棧來講,一般都是有一定的空間大小的。另外,棧是機器系統提供的資料結構,計算機會在底層對棧提 供支援:分配專門的暫存器存放棧的位址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是c/c++函式庫提供的,它的機制是很複雜的,例 如為了分配一塊記憶體,庫函式會按照一定的演算法(具體的演算法可以參考資料結構/作業系統)在堆記憶體中搜尋可用的足夠大小的空間,如果沒有足夠大小的空間(可 能是由於頻繁的malloc/free造成記憶體空間的不連續,從而造成大量的碎片),就有可能呼叫系統功能去增加程式資料段的記憶體空間,這樣就有機會分到 足夠大小的記憶體,然後進行返回。顯然,堆的效率比棧要低得多。

全域性資料區:用來存放全域性變數和靜態變數。存在於程式的整個執行期間,是由編譯器分配和釋放的。一般又細分為資料段和bss段,初始化的全域性變數放在資料段,未初始化的全域性變數放在bss段。

文字常量區:例如char *pchr = "in2kernel",則"in2kernel"為文字常量,存放於文字常量區。也由編譯器控制分配和釋放。

程式**區:也稱為正文段,用來存放二進位制**(cpu執行的機器指令部分)。

記憶體分配方式

記憶體分配方式有三種:

1 從靜態儲存區域分配。內存在程式編譯的時候就已經分配好,這塊內存在程式的整個執行期間都存在。例如全域性變數,static變數。

2 在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。

3 從堆上分配,亦稱動態記憶體分配。程式在執行的時候用malloc或calloc申請任意多少的記憶體,程式設計師自己負責在何時用free釋放記憶體。動態記憶體的生存期由我們決定,使用非常靈活,但問題也最多。

常見的記憶體錯誤及其對策

1 記憶體分配未成功,卻使用了它。

編 程新手常犯這種錯誤,因為他們沒有意識到記憶體分配會不成功。常用解決辦法是,在使用記憶體之前檢查指標是否為null。如果指標p是函式的引數,那麼在函式 的入口處用assert(p!=null)進行檢查。如果是用malloc或calloc來申請記憶體,應該用if(p==null) 或if(p!=null)進行防錯處理。

2 記憶體分配雖然成功,但是尚未初始化就引用它。

犯這種錯誤主要有兩個起因:一是 沒有初始化的觀念;二是誤以為記憶體的預設初值全為零,導致引用初值錯誤(例如陣列)。記憶體的預設初值究竟是什麼並沒有統一的標準,儘管有些時候為零值,我 們寧可信其無不可信其有。所以無論何種方式建立陣列,都別忘了賦初值,即便是賦零值也不可省略,不要嫌麻煩。

5 釋放了記憶體卻繼續使用它。

使用free或delete釋放了記憶體後,沒有將指標設定為null。導致產生"野指標"。

6 不清楚指標運算

指標加上乙個整數的結果是另乙個指標。問題是,它指向哪兒?如果你將乙個字元指標加上1,運算結果產生的指標指向記憶體的下乙個字 符。如果你將乙個指向int的指標加1,結果還會是指向下乙個字元嗎?答案是否定的,事實上, p+n 等於 (size_t)p + n * sizeof(*p)。另外,對指標作關係運算也是有限制的,前提是它們都要指向同乙個陣列中的元素。標準允許指向陣列元素的指標與指向陣列最後乙個元素 後面的那個記憶體位置的指標比較,不允許與指向第1個元素之前的那個記憶體位置的指標進行比較。

C語言之記憶體使用

問題 記憶體使用 有人寫了乙個將整數轉換為字串的函式 char itoa int n 如果我呼叫這個函式 char str5 itoa 5 str5會是什麼結果呢?答案分析 答案是不確定,可以確定的是肯定不是我們想要的 5 retbuf定義在函式體中,是乙個區域性變數,它的記憶體空間位於棧 stac...

C語言之記憶體分配函式

include include include intmain printf n free pm pm null int pc pc int calloc 100,sizeof int printf 使用calloc分配的儲存空間 n for int i 0 i 100 i printf n fre...

C C 語言之記憶體分配

一.理論 乙個由c c 編譯的程式占用的記憶體分為以下幾個部分 1 棧區 stack 由編譯器自動分配釋放 存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。2 堆區 heap 一般由程式設計師分配釋放,c語言中對應的主要函式有malloc 和free c 中是new和delete...