JM8.6以內存分配——基礎篇

  在研究JM8.6中內存分配模塊(memalloc.c)時,看到以下代碼:算法

  若是C語言基礎較好的話,對上面也比較好理解。函數

  可是再看到下面:工具

  以及再下面:佈局

  可真得花點時間去琢磨內存如何佈局的,以及如何訪問到指望位置的值。spa

  本篇文章就準備將背景知識和上面的三個內存分配函數,介紹一下,以供有此困惑的人來理解。3d

  其實,很早以前就有該想法,針對C語言的指針來作一次科普,但因爲拖延症的緣故一直沒動筆。指針

  本篇是基礎篇,後面會再開一篇來介紹上面三個函數的原理及內存佈局。code

1. 什麼是指針?blog

  所謂指針,就是某個地址空間,存儲着一個值(指針值),這個值爲某個內存地址。內存

  以下圖:(請原諒我拙劣的畫圖水平,拿win10自帶的繪圖工具畫的。。。)

  

  拿32位系統來進行說明,每一個指針(無論什麼類型的指針——內置類型或自定義類型)的sizeof都爲4Bytes,而且爲

了高效訪問,通常都是4字節對齊的(存儲ptr值的這段內存地址addr2,打印其值,最後兩個二進制位爲0)。

  上圖中,內存空間addr2中存儲着一個指針值——ptr(ptr的值爲addr1),即這個ptr指針指向addr1這個地址空間。

2. 棧指針 & 堆指針

  計算機系統中兩種內存類型——stack和heap,stack爲棧內存,如函數內臨時變量、函數參數,heap爲堆內存,如malloc

分配的空間,其從系統中獲取,通常分配和回收使用夥伴算法(buddy)。

  其中stack增加方向向下,heap增加方向向上,以下demo及打印:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void stack_test()
 5 {
 6     int tmp0;
 7     int tmp1;
 8     int tmp2;
 9     printf("stack_addr: &tmp0=%p, &tmp1=%p, &tmp2=%p\n", &tmp0, &tmp1, &tmp2);
10 }
11 
12 void heap_test()
13 {
14     char *ptr0 = (char*)malloc(64);
15     char *ptr1 = (char*)malloc(64);
16     char *ptr2 = (char*)malloc(64);
17     printf("heap_addr: ptr0=%p, ptr1=%p, ptr2=%p\n", ptr0, ptr1, ptr2);
18 }
19 
20 int main(void)
21 {
22     stack_test();
23     heap_test();
24 }

  從運行結果看,tmp0~2這種stack變量的地址,從高地址往低地址變化,而ptr0~2這種指向heap空間的值,從低往高變化。

然而,ptr0~2做爲stack類型變量,其地址仍符合stack的增加方向(從高往低變化)。不信能夠打印出&ptr0, &ptr1, &ptr2的值。

3. 如何給一個指針變量賦值?

  使用以下方式:

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 void mem_alloc(char **pp)  5 {  6     *pp = (char*)malloc(64);  7 }  8 
 9 int main() 10 { 11     char *ptr0; 12     char *ptr1; 13     char *ptr2; 14 
15     char ch = 'A'; 16     ptr0 = &ch;                 //ptr0指向stack變量ch
17     ptr1 = (char*)&ptr2;        //ptr1指向ptr2這個stack變量的地址
18     mem_alloc(&ptr2);           //給ptr2這個stack變量賦值,賦值爲heap空間地址
19     printf("stack_addr: &ptr0=%p, &ptr1=%p, &ptr2=%p, &ch=%p\n", &ptr0, &ptr1, &ptr2, &ch); 20     printf("ptr_val: ptr0=%p, ptr1=%p, ptr2=%p\n", ptr0, ptr1, ptr2); 21 }

  須要注意一點的是,若是經過函數調用給一個變量初始化,那麼參數必須是該變量的地址,如18行的:mem_alloc(&ptr2);

  爲何?

  傳地址才能修改該地址處的值(ptr2這個stack變量的內存地址空間中,所保存的值——指向哪兒),而傳值只是進行了一份數據拷貝,

等調用的函數退出後,原先被拷貝的變量什麼都沒改變。

  所以,若是想修改15行中ch這個stack變量的值,就傳其地址:&ch;若是想修改13行的ptr2這個stack變量的值,也傳其地址:&ptr2,

正如18行中所調用的。

4. 指針、雙指針、三指針、四指針

  指針也能夠稱爲單指針,相似於這種:void* ptr; 如上面代碼中的ptr0,ptr1,ptr2。

  雙指針爲指向指針的指針,相似於:void** pptr; 如第4行中的形參:void mem_alloc(char **pp)。

  三指針其實又多了一個*,形如:void*** ppptr; 能夠理解爲一個指針指向一個雙指針,而該三指針變量值(該變量內存空間中的值)爲第一個指針值。

  四指針也又多了一個*,形如:void**** pppptr; 再多一道中轉。

  畫個圖來表達:

  

   其中,存儲字符的空間我故意畫小,由於其大小爲1Byte,而指針的大小爲4Bytes。

相關文章
相關標籤/搜索