某日二師兄參加XXX科技公司的C++工程師開發崗位第17面: > 面試官:聊一聊指針? > > 二師兄:好的。 > > 面試官:你覺得指針本質上是什麼? > > 二師兄:這要從記憶體地址開始說起了。如果有一塊容量是1G的記憶體,假設它的地址是從`0x00000000` 到`0x3fffffff`,每一個 ...
某日二師兄參加XXX科技公司的C++工程師開發崗位第17面:
面試官:聊一聊指針?
二師兄:好的。
面試官:你覺得指針本質上是什麼?
二師兄:這要從記憶體地址開始說起了。如果有一塊容量是1G的記憶體,假設它的地址是從
0x00000000
到0x3fffffff
,每一個位元組都對應一個地址。當我們聲明一個變數並初始化它時:
int a = 42;
二師兄:操作系統會分配一塊容量為
4(sizeof(int))
的地址,這塊記憶體的首地址是0x00001000
(假設),結束地址是0x00001003
,在申請的這4
個位元組上放入42
。當我們對這個變數取地址時,
int a = 42;
int* p = &a;
二師兄:操作系統會再分配一塊記憶體,這塊記憶體的大小是
sizeof(int*)
,這塊記憶體的起始地址是0x00002000
(假設),結束地址是0x00002003
(32位操作系統),然後將&a
取到的起始地址0x00001000
放入0x00002000
-0x00002003
中。並將剛分配的這塊記憶體的起始地址賦給p
。
二師兄:當我們對
p
操作時,是對0x00002000-0x00002003
這塊記憶體操作,當我們對*p
(解引用)操作時,是對0x00001000-0x00001003
這塊記憶體操作。二師兄:回到問題,我覺得指針的本質就是記憶體地址。雖然指針指向一塊記憶體地址,但它同時也是一個變數,也可以對指針取地址。如果對指針取地址,同樣可以得到一個記憶體地址(如
0x00002000
),如果把這個記憶體地址存起來,那麼指向這個記憶體地址的變數的類型就是二級指針(int**
)。面試官:好的。在
0x00002000-0x00002003
這塊記憶體中,我們放入了一個地址是0x00001000
,但是並沒有這個地址的長度。只知道一個地址而不知道長度,怎麼能把數據取出來?二師兄:這主要是因為
p
的類型是int*
,當對p
解引用時,編譯器知道瞭解引用的結果是int
類型,所以從0x00001000
往後讀取4個位元組(sizeof(int)
),並按照當前CPU的模式(考慮大小端)把這四個位元組組成一個int
類型的變數。面試官:
malloc
函數你知道吧,返回的類型是void*
,在free
的時候怎麼知道這塊記憶體的大小的呢?二師兄:額。。這個還不太清楚。。
面試官:沒關係,今天就到這裡,回去等通知吧。
讓我們來看看讓二師兄折戟的這個問題:
malloc
函數返回的類型是void*
,在free
的時候怎麼知道這塊記憶體的大小的呢?
這裡牽扯到malloc
和free
的實現方式,不同的廠商實現的方式不盡相同。以ptmalloc
為例,當使用malloc
申請size = 16
的記憶體時,malloc
會從記憶體池中分配一塊sizeof(chunk)+16
長度的記憶體。chunk
段保存了一些前後chunk
的信息,也保存了這塊記憶體的大小(16)。malloc
函數返回的地址是0x00001000
,而在free(0x00001000)
時,free
函數會用0x00001000
減去特定值(sizeof(chunk)
),得到chunk
的起始地址,從chunk
中獲取這塊記憶體真正的尺寸,從而完成free
的任務。拋開記憶體的利用率不說,這是一個非常美妙的實現!
好了,今日份面試到這裡就結束了。關註我,每天帶你學習一個C++小知識!
關註我,帶你21天“精通”C++!(狗頭)