C高階4:內存

1. 結構體字節(jié)對齊

  • 試一試
struct S1{
    char c1;
    char c2;
    int n;
};
struct S2{
    char c1;
    int n;
    char c2;
};

printf("sizeof(struct S1) = %ld\n",sizeof(struct S1));
printf("sizeof(struct S2) = %ld\n",sizeof(struct S2));

在C語言里狸剃,結構體所占的內存是連續(xù)的粮宛,但是各個成員之間的地址不一定是連續(xù)的滞时。所以就出現了"字節(jié)對齊"叁幢。

  • 字節(jié)對齊默認原則

    1. 結構體變量的大小,一定是其最大的數據類型的大小的整數倍坪稽,如果某個數據類型大小不夠曼玩,就填充字節(jié)鳞骤。
    2. 結構體變量的地址,一定和其第一個成員的地址是相同的演训。
  • 練習

struct Box{
    int height;
    char a[10];
    double width; 
    char type;
};

int main(void) {
    struct Box box;
    printf("box = %p\n", &box);
    printf("box.height = %p\n", &box.height);
    printf("box.a = %p\n", box.a);
    printf("box.width = %p\n", &box.width);
    printf("box.type = %p\n", &box.type);
    printf("box = %d\n", sizeof(box));
    return 0;
}

2. 內存四區(qū)

執(zhí)行下面代碼弟孟,分析代碼中各種變量的地址特點。

#include <stdio.h>
#include <stdlib.h>

void f1(){
  int f1local1;
  int f1local2;
  static int f1static1;
  static int f1static2;
  int* f1dynamic1 = malloc(sizeof(int));
  int* f1dynamic2 = malloc(sizeof(int));
  printf("--------------f1()----------------\n");
  printf("&f1local1   = %p\n",&f1local1);
  printf("&f1local2   = %p\n",&f1local2);
  printf("&f1static1  = %p\n",&f1static1);
  printf("&f1static2  = %p\n",&f1static2);
  printf("f1dynamic1  = %p\n",f1dynamic1);
  printf("f1dynamic2  = %p\n",f1dynamic2);
  printf("\"f1string1\" = %p\n","f1string1");
  printf("\"f1string2\" = %p\n","f1string2");
  printf("--------------f1()----------------\n");
  free(f1dynamic1);
  free(f1dynamic2);
}
void f2(){
  int f2local1;
  int f2local2;
  static int f2static1;
  static int f2static2;
  int* f2dynamic1 = malloc(sizeof(int));
  int* f2dynamic2 = malloc(sizeof(int));
  printf("--------------f2()----------------\n");
  printf("&f2local1   = %p\n",&f2local1);
  printf("&f2local2   = %p\n",&f2local2);
  printf("&f2static1  = %p\n",&f2static1);
  printf("&f2static2  = %p\n",&f2static2);
  printf("f2dynamic1  = %p\n",f2dynamic1);
  printf("f2dynamic2  = %p\n",f2dynamic2);
  printf("\"f2string1\" = %p\n","f2string1");
  printf("\"f2string2\" = %p\n","f2string2");
  printf("--------------f2()----------------\n");
  free(f2dynamic1);
  free(f2dynamic2);
}

int static1;
int static2;
int main(){
  int local1;
  int local2;
  int* dynamic1 = malloc(sizeof(int));
  int* dynamic2 = malloc(sizeof(int));
  printf("&local1   = %p\n",&local1);
  printf("&local2   = %p\n",&local2);
  printf("&static1  = %p\n",&static1);
  printf("&static2  = %p\n",&static2);
  printf("dynamic1  = %p\n",dynamic1);
  printf("dynamic2  = %p\n",dynamic2);
  printf("\"string1\" = %p\n","string1");
  printf("\"string2\" = %p\n","string2");
  printf("&f1 = %p\n",&f1);
  printf("&f2 = %p\n",&f2);
  f1();
  f2();
}

分析執(zhí)行結果

&local1   = 0x7ffc8b8120fc
&local2   = 0x7ffc8b8120f8
&static1  = 0x601060
&static2  = 0x601064
dynamic1  = 0x1d10010
dynamic2  = 0x1d10030
"string1" = 0x400b8f
"string2" = 0x400ba7
&f1 = 0x40060d
&f2 = 0x400707
--------------f1()----------------
&f1local1   = 0x7ffc8b8120cc
&f1local2   = 0x7ffc8b8120c8
&f1static1  = 0x601050
&f1static2  = 0x601054
f1dynamic1  = 0x1d10050
f1dynamic2  = 0x1d10070
"f1string1" = 0x400a2f
"f1string2" = 0x400a4b
--------------f1()----------------
--------------f2()----------------
&f2local1   = 0x7ffc8b8120cc
&f2local2   = 0x7ffc8b8120c8
&f2static1  = 0x601058
&f2static2  = 0x60105c
f2dynamic1  = 0x1d10070
f2dynamic2  = 0x1d10050
"f2string1" = 0x400af7
"f2string2" = 0x400b13
--------------f2()----------------

上面結果每次執(zhí)行結果會有所變化样悟,不同計算機結果也會不同拂募。但是會有如下規(guī)律:

  1. 局部變量、靜態(tài)變量窟她、動態(tài)分配內存陈症、字符串常量與函數分別放在一起,即使在不同的函數中震糖。
  2. 變量的存放地址大小有如下特點:

    字符串常量與代碼 < 靜態(tài)變量 < 動態(tài)分配內存 < 局部變量

  3. 靜態(tài)變量录肯、動態(tài)分配內存、字符串常量與函數的相鄰變量地址是遞增的吊说。局部變量相鄰變量地址是遞減的论咏。
  4. 字符串常量與函數是在一起的。

上面說明代碼在內存中是按類型存放在不同的區(qū)里面的颁井。

gcc -S test.c
gcc --save-temp test.c
readelf -S ./a.out

2.1 棧區(qū)(stack)

由編譯器自動分配和釋放厅贪,主要是存放函數參數的值,局部變量的值雅宾。

2.2 堆區(qū)(heap)

由程序員自己申請分配和釋放养涮,需要malloc()calloc()眉抬、realloc()函數來申請贯吓,用free()函數來釋放如果不釋放,可能出現指針懸空/野指針蜀变。

函數不能返回指向棧區(qū)的指針悄谐,但是可以返回指向堆區(qū)的指針。

2.3 數據區(qū)(data)

變量標有static關鍵字库北,保存了靜態(tài)變量爬舰。
1. 初始化的全局變量和初始化的靜態(tài)變量,在一塊區(qū)域贤惯;
2. 未初始化的全局變量和未初始化的靜態(tài)變量洼专,在一塊區(qū)域棒掠,稱作BSS(Block Started by Symbol:以符號開始的塊)孵构;
3. 靜態(tài)變量的生命周期是整個源程序,而且只能被初始化一次烟很,之后的初始化會被忽略颈墅。
(如果不初始化蜡镶,數值數據將被默認初始化為0, 字符型數據默認初始化為NULL)。

整個數據區(qū)的數組恤筛,在程序結束后由系統(tǒng)統(tǒng)一銷毀官还。

2.4 代碼區(qū)(code)

用于存放編譯后的可執(zhí)行代碼,二進制碼毒坛,機器碼望伦。

3. 堆和棧的區(qū)別

No. 比較方面
1 管理方式 由系統(tǒng)自動管理,以執(zhí)行函數為單位 由程序員手動控制
2 空間大小 空間大小編譯時確定(參數+局部變量) 具有全局性煎殷,總體無大小限制屯伞。
3 分配方式 函數執(zhí)行,系統(tǒng)自動分配豪直;函數結束劣摇,系統(tǒng)立即自動回收。 使用new/malloc()手動分配釋放弓乙;使用delete/free()手動釋放
4 優(yōu)點 使用方便末融,不需要關心內存申請釋放。 可以跨函數使用暇韧。
5 缺點 只能在函數內部使用勾习。 容易造成內存泄露。

4. 顯示目標文件區(qū)段大邢橇:size命令

  • 各區(qū)段含義

    No. 區(qū)段 名稱 含義
    1 text 代碼段(code segment/text segment) 存放程序執(zhí)行代碼的內存區(qū)域语卤。該區(qū)域的大小在運行前已確定,且通常屬于只讀酪刀〈舛妫可能包含一些只讀的常數變量,例如字符串常量等骂倘。
    2 data 數據段(data segment) 存放程序中已初始化的全局變量的內存區(qū)域眼滤。數據段屬于靜態(tài)內存分配。
    3 bss BSS段(bss segment) 存放程序中未初始化的全局變量的內存區(qū)域历涝。BSS是英文Block Started by Symbol的簡稱诅需。BSS段屬于靜態(tài)內存分配。

    dechex是前面三個區(qū)域的和荧库,dec是十進制堰塌,hex是十六進制。

  • 沒有顯示的區(qū)段

    No. 區(qū)段 含義
    1 棧(stack) 存放程序臨時創(chuàng)建的局部變量分衫,也就是函數括弧{}中定義的變量(不包括static聲明的變量)场刑。在函數被調用時,參數也會被壓入發(fā)起調用的進程棧中蚪战,并且待到調用結束后牵现,函數的返回值也會被存放回棧中铐懊。
    2 堆(heap) 存放程序動態(tài)分配的內存段,大小并不固定瞎疼,可動態(tài)擴張或縮減科乎。當調用malloc()等函數分配內存時,堆被擴張贼急;當調用free()等函數釋放內存時茅茂,堆被縮減。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末太抓,一起剝皮案震驚了整個濱河市玉吁,隨后出現的幾起案子,更是在濱河造成了極大的恐慌腻异,老刑警劉巖进副,帶你破解...
    沈念sama閱讀 210,835評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異悔常,居然都是意外死亡影斑,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 89,900評論 2 383
  • 文/潘曉璐 我一進店門机打,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矫户,“玉大人,你說我怎么就攤上這事残邀〗粤桑” “怎么了?”我有些...
    開封第一講書人閱讀 156,481評論 0 345
  • 文/不壞的土叔 我叫張陵芥挣,是天一觀的道長驱闷。 經常有香客問我,道長空免,這世上最難降的妖魔是什么空另? 我笑而不...
    開封第一講書人閱讀 56,303評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮蹋砚,結果婚禮上扼菠,老公的妹妹穿的比我還像新娘。我一直安慰自己坝咐,他們只是感情好循榆,可當我...
    茶點故事閱讀 65,375評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著墨坚,像睡著了一般秧饮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,729評論 1 289
  • 那天浦楣,我揣著相機與錄音,去河邊找鬼咪辱。 笑死振劳,一個胖子當著我的面吹牛,可吹牛的內容都是我干的油狂。 我是一名探鬼主播历恐,決...
    沈念sama閱讀 38,877評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼专筷!你這毒婦竟也來了弱贼?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,633評論 0 266
  • 序言:老撾萬榮一對情侶失蹤磷蛹,失蹤者是張志新(化名)和其女友劉穎吮旅,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體味咳,經...
    沈念sama閱讀 44,088評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡庇勃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,443評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了槽驶。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片责嚷。...
    茶點故事閱讀 38,563評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖掂铐,靈堂內的尸體忽然破棺而出罕拂,到底是詐尸還是另有隱情,我是刑警寧澤全陨,帶...
    沈念sama閱讀 34,251評論 4 328
  • 正文 年R本政府宣布爆班,位于F島的核電站,受9級特大地震影響辱姨,放射性物質發(fā)生泄漏蛋济。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,827評論 3 312
  • 文/蒙蒙 一炮叶、第九天 我趴在偏房一處隱蔽的房頂上張望碗旅。 院中可真熱鬧,春花似錦镜悉、人聲如沸祟辟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旧困。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吼具,已是汗流浹背僚纷。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拗盒,地道東北人怖竭。 一個月前我還...
    沈念sama閱讀 46,240評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像陡蝇,于是被迫代替她去往敵國和親痊臭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,435評論 2 348

推薦閱讀更多精彩內容

  • 一登夫、溫故而知新 1. 內存不夠怎么辦 內存簡單分配策略的問題地址空間不隔離內存使用效率低程序運行的地址不確定 關于...
    SeanCST閱讀 7,781評論 0 27
  • 文章也同時在個人博客 http://kimihe.com/更新 引言 網絡上關于內存中各區(qū)段作用的文章有很多广匙,但不...
    QihuaZhou閱讀 37,747評論 12 135
  • 1. 基礎知識 1.1、 基本概念恼策、 功能 馮諾伊曼體系結構1鸦致、計算機處理的數據和指令一律用二進制數表示2、順序執(zhí)...
    yunpiao閱讀 5,266評論 1 22
  • 第一天 一.內聯函數(inline) 函數調用的時候需要建立棧內存環(huán)境涣楷,進行參數傳遞蹋凝,并產生程序執(zhí)行轉移,這些工作...
    陳果123閱讀 1,118評論 0 1
  • 我會什么呢?不過是吃吃睡睡 我會什么呢情龄?不過是憧憬未來 我會什么呢迄汛?不過是抱怨生活 我會什么呢?不過是無所事事 ...
    本人女生閱讀 284評論 1 2