引子:linux
#include<stdio.h> int main() { char*p =」tiger」; p[1]=’I’; p++; printf(「%s\n」,p); }
編譯執行後提示:段錯誤
程序員
簡單分析:數據結構
char *p ="tiger"; 系統在棧上開闢了4個字節存儲p的數值,其中"tiger"在只讀存儲區中存儲,所以"tiger"的內容不能改變,*p="tiger",表示地址賦值,所以,p指向了只讀存儲區,所以改變p指向的內容會引發段錯誤。可是由於p自己內容是存放在棧上,所以p的數值是能夠改變的,所以p++是正確的。函數
上述出現了棧、只讀存儲區 這些都是C程序中各個不一樣存儲部分的名稱,瞭解了C程序的存儲分佈能夠有效的下降coding過程出現段錯誤的概率。spa
C程序通過編譯-連接-重定位後就會生成一個有二進制機器代碼組成的可執行文件,通常有以下幾個部分組成:
命令行
.text 代碼段
code
CPU執行的機器指令部分。代碼段一般是能夠共享的,因此在運行時被多個進程使用也只需有一個副本,另外,正文段經常是隻讀的,以防止程序因爲意外事故而修改其自身的指令。另外,代碼段還規定了局部變量申請內存空間的信息進程
.data 數據段內存
程序中被初始化的全局變量,靜態變量以及字符串常量(即上述所說的只讀存儲區)字符串
.bss 未初始化數據段
未初始化的全局或者靜態變量放置於此。因爲是未初始化,因此加載至內存後內核會將此段初始化爲0
當程序加載至內存後有須要堆和棧來存放運行時存取的數據
堆 heap (動態存儲區)
自下而上增加,通常有程序員本身分配(malloc)和釋放(free),分配速度較慢,但因爲是採用鏈式非連續地址的數據結構因此靈活度比較大,通常32bit系統下堆能夠分配到4G內存,但容易產生內存碎片,關於則方面能夠參考下linux的內存分配機制slab和buddy的有機結合
棧 stack
自頂向下增加,由系統自動分配,分配速度較快,因爲是系統事先分配的連續地址內存會受限於OS預設的大小,超出即出現overflow,linux下可使用ulimit -a查看當前棧大小和-s 設置棧帶下。再棧中保存着函數調用的環境變量,在進行函數調用時入棧順序爲:函數調用完後須要執行的語句-->函數調用參數,通常是從右向左入棧-->最後就是函數的局部變量,函數調用完後再依次出棧
C程序內存分佈圖:
++++++++++++++++++++++ 高地址
命令行參數和環境變量
++++++++++++++++++++++
棧, 向下增加
++++++++++++++++++++++
堆,向上增加
++++++++++++++++++++++
bss段
++++++++++++++++++++++
data段
++++++++++++++++++++++
text段
++++++++++++++++++++++ 低地址
你們可使用objdump或者readelf來查看下ELF格式的程序中各個段的詳細信息