linux c的指針與內(nèi)存

指針

指針的聲明用*a來表示生逸,指針是保存內(nèi)存地址的一種數(shù)據(jù)類型柜砾。另外赵刑,取地址用&a來做玲躯。

指針的調(diào)用和傳值

int a = 100;
int point_t(int *a)
...
point_t(&a)

內(nèi)存

計算機可以控制嚼锄、接收電流的高(1)低(0)電位或者通(1)斷(0)電路减拭,這就產(chǎn)生了計算機能識別的二進制。

內(nèi)存的最小單位是字節(jié)(Byte区丑,1 Byte = 8 bits拧粪,一個字節(jié)是八個二進制位),一個字節(jié)可以表示00000000至11111111種意義(可以表示0~255元素)沧侥。

一個十六進制的數(shù)字可以表示4位二進制的數(shù)字(1111 = 0xf)可霎。一個字節(jié),既可以用8個二進制數(shù)字表示宴杀,也可以用2個16進制的數(shù)字表示癣朗。

32位操作系統(tǒng)

32位os的cpu地址總線是32位,支持232 個地址位旺罢,暨尋址空間是32位旷余,最多能訪問0~232次方(大約4GB空間)個內(nèi)存地址,可以理解為只能訪問并操縱最多4GB的內(nèi)存空間扁达。每個內(nèi)存地址位記錄一個唯一的內(nèi)存地址編號荣暮,每個地址編號對應存儲一個字節(jié)。

證明:
232=210 * 210 * 210 * 2 2
= 1024 byte * 1024 byte * 1024 byte * 4
= 1kb * 1024 byte * 1024 byte * 4
= 1mb * 1024 byte * 4
= 1gb * 4 = 4gb

內(nèi)存管理

內(nèi)存由os統(tǒng)一管理(編號罩驻、規(guī)劃內(nèi)存)穗酥,內(nèi)存大小的也會將多根內(nèi)存條合并后統(tǒng)一計算。os還會對多個程序進行統(tǒng)一調(diào)度惠遏、分配內(nèi)存空間砾跃,防止不同程序?qū)τ趦?nèi)存的相互侵占。

64位os內(nèi)存管理草圖

例如节吮,64位os抽高,應用程序使用前48位,暨0x7fffffffffffffff以下的內(nèi)存地址位透绩,系統(tǒng)內(nèi)核使用后邊的16位內(nèi)存地址位翘骂。

這樣把用戶的內(nèi)存和os的內(nèi)存隔離開,還有個好處就算帚豪,os的內(nèi)存不會被大量占用碳竟,避免機器卡住、卡死狸臣、死機等狀態(tài)的發(fā)生莹桅。因此,只要os可用烛亦,就可以用os將關閉應用程序诈泼,解決安全等問題懂拾。

內(nèi)存規(guī)劃

如上圖所示,os把內(nèi)存進行了分片铐达,分為系統(tǒng)內(nèi)核岖赋、棧、自由內(nèi)存區(qū)瓮孙、堆唐断、數(shù)據(jù)段、代碼段

代碼段

代碼被編譯后衷畦,會存到磁盤中栗涂,形成2進制文件。運行這個程序(例如祈争,調(diào)用main函數(shù))斤程,其實就是os把二進制數(shù)據(jù)文件(也就是計算機指令)加載到內(nèi)存代碼段中。C語言不能直接操作代碼段的地址菩混。

在代碼段忿墅,可以知道程序的二進制字節(jié)大小。例如定義如下函數(shù):

p &rect 0x4005a6
p &quadrate 0x4005dd

用quadrate 的地址高度減去rect的地址高度沮峡,就是加載到內(nèi)存中rect函數(shù)的大小

數(shù)據(jù)段

數(shù)據(jù)段存儲靜態(tài)變量疚脐、全局變量、常量邢疙,他們都會分配獨立的地址棍弄,且地址唯一

堆內(nèi)存

棧內(nèi)存

棧內(nèi)存記錄變量的地址和值,還會記錄程序已經(jīng)執(zhí)行了多少行的行號疟游,記錄程序當前狀態(tài)呼畸,調(diào)用哪個函數(shù),函數(shù)中有哪些變量颁虐,變量值蛮原。

變量名其實就是地址別名,變量其實就是內(nèi)存地址另绩,系統(tǒng)通過變量告訴cpu要到哪個地址取數(shù)據(jù)儒陨。

#include <stdio.h>
int global = 0;

int rect(int a, int b)
{
    static int count = 0;
    count++;
    global++;
    int s = a * b;
    return s;
}

int quadrate(int a)
{
    static int count = 0;
    count++;
    global++;
    int s = rect(a, a);
    return s;
}

int main()
{
    int a = 3;
    int b = 4;
    int *pa = &a;
    int *pb = &b;
    int *pglobal = &global;
    int (*pquadrate)(int a) = &quadrate;
    int s = quadrate(a);
    int s2 = (*pquadrate)(a);//定義一個函數(shù)指針
    printf("%d\n", s);
    return 0;
}

操作系統(tǒng)對于內(nèi)存的管理

代碼端

gcc編譯器對于代碼是如何優(yōu)化的

函數(shù)棧就不一樣了,一個函數(shù)可用被多次調(diào)用笋籽,一個變量也會被多次調(diào)用

gcc會優(yōu)化存儲
我們在 中看到的地址蹦漠,例如0x7fffffffddfc就是一個整型變量的首地址,然后ddfc干签、ddfd津辩、ddfe、ddff都是這個整形變量的地址容劳。(因為喘沿,一個整形變量占用四個字節(jié),四八32竭贩,一個整形是32bits)

但是 gcc會做優(yōu)化

不連續(xù)賦值蚜印,編譯器會優(yōu)化,為了讓cpu操作指令更方便更快留量,為了提升程序的執(zhí)行效率窄赋,因此,會對源代碼進行優(yōu)化楼熄。那么編譯之后的指令存儲忆绰,跟我們編寫的代碼的順序可能會不一樣。例如可岂,會先定義基本類型的错敢,然后將基本類型的地址連續(xù)放到內(nèi)存中,然后再放其他類型的缕粹,都是把同一類型的變量放到一起稚茅。這樣可用讓程序執(zhí)行更快,至于為什么平斩,下面會說亚享。另外,64位操作系統(tǒng)下绘面,指針占8個字節(jié)(32位操作系統(tǒng)欺税,指針占4個字節(jié)),因為揭璃,是64bits晚凿,一個字節(jié)存8個bits,因此塘辅,需要8個字節(jié)才能將全部的地址存儲下來晃虫。

棧這個內(nèi)存空間,保存的就是函數(shù)當前運行的狀態(tài)扣墩。包括代碼執(zhí)行到多少行指令哲银,每一個內(nèi)存空間到底是什么類型的數(shù)據(jù),什么數(shù)值呻惕。在棧中荆责,函數(shù)或者變量會被多次調(diào)用,每次調(diào)用都會分配新的獨立的棧地址亚脆。函數(shù)調(diào)用就是先進后廚的棧內(nèi)存結構做院。因此,越到棧頂?shù)暮瘮?shù)的地址越小。棧是從后向前壓棧的键耕。棧寺滚,越往后調(diào)用的地址越小。從棧頂向下分配的屈雄。

函數(shù)指針

函數(shù)指針定義后村视,也可以調(diào)用函數(shù),這種做法經(jīng)常用在我們做 回調(diào)函數(shù)來使用

一個地址酒奶,用括號包起來蚁孔,表示指向一個代碼段的函數(shù)。

帶*號表示要訪問地址對應的字節(jié)塊是啥

數(shù)組惋嚎、動態(tài)堆類型創(chuàng)建杠氢、指針運算

數(shù)組申明的內(nèi)存排列

C語言中的數(shù)據(jù)聲明,也是在棧內(nèi)存中保存的
c語言不做指針代碼的安全檢測另伍。因為鼻百,地址是連續(xù)排放的,因此质况,指針運算符就用上了

指針運算

指針偏移愕宋,的運行效率非常高,性能非常好结榄,這樣比cpu根據(jù)地址總線取地址要更方便一些

int *p=&a;

p+=3;表示將指針偏移3個int 變量占位符中贝。

在指針上做的加個減,其實做的是地址的偏移臼朗。

數(shù)組其實就是一種地址的表示

int array[3];

可用表示為邻寿,int p = array;
此時,
p也就指向了array數(shù)組的第一個元素的地址视哑。

因此我們這樣寫

p[0] == array[0];
p[1] == array[1];
p[2] == array[2];

因此绣否,在c中,任何用數(shù)組操作的地方挡毅,都可以用c來代替蒜撮。因此,數(shù)組是一種指針常量跪呈。但是 段磨,指針是指針變量。因此耗绿,定義了數(shù)組苹支,數(shù)組就永遠指向某個地址

但是 ,指針指向的地址是會改變的
這就是區(qū)別误阻。

字符數(shù)組和指針字符串

字符串 指針 竟然 存在 代碼段债蜜?

注意:c語言字符串數(shù)組晴埂,以\0結尾,什么時候遇到\0也就標識著字符串結束了寻定。

malloc可以分配地址

c語言字符串是原始字符串儒洛,其實就是字節(jié)數(shù)組。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末特姐,一起剝皮案震驚了整個濱河市晶丘,隨后出現(xiàn)的幾起案子黍氮,更是在濱河造成了極大的恐慌唐含,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沫浆,死亡現(xiàn)場離奇詭異捷枯,居然都是意外死亡,警方通過查閱死者的電腦和手機专执,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門淮捆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人本股,你說我怎么就攤上這事攀痊。” “怎么了拄显?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵苟径,是天一觀的道長。 經(jīng)常有香客問我躬审,道長棘街,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任承边,我火速辦了婚禮遭殉,結果婚禮上,老公的妹妹穿的比我還像新娘博助。我一直安慰自己险污,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布富岳。 她就那樣靜靜地躺著蛔糯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪城瞎。 梳的紋絲不亂的頭發(fā)上渤闷,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音脖镀,去河邊找鬼飒箭。 笑死狼电,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的弦蹂。 我是一名探鬼主播肩碟,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼凸椿!你這毒婦竟也來了削祈?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤脑漫,失蹤者是張志新(化名)和其女友劉穎髓抑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體优幸,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡吨拍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了网杆。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羹饰。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖碳却,靈堂內(nèi)的尸體忽然破棺而出队秩,到底是詐尸還是另有隱情,我是刑警寧澤昼浦,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布馍资,位于F島的核電站,受9級特大地震影響座柱,放射性物質(zhì)發(fā)生泄漏迷帜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一色洞、第九天 我趴在偏房一處隱蔽的房頂上張望戏锹。 院中可真熱鬧,春花似錦火诸、人聲如沸锦针。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽奈搜。三九已至,卻和暖如春盯荤,著一層夾襖步出監(jiān)牢的瞬間馋吗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工秋秤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宏粤,地道東北人脚翘。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像绍哎,于是被迫代替她去往敵國和親来农。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容