- 簡單說一下c語言中malloc函數的動態分配
malloc函數在linux終端下,敲 man malloc 就可以看到手冊中malloc函數的詳細介紹。可是。。。手冊都是英文的啊!對於英文不好的我,讀起來還是挺生硬。。。
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
void *reallocarray(void *ptr, size_t nmemb, size_t size);
以上這些函數呢,就是讓程序猿來手動分配程序所需要的空間大小。函數用起來簡單,重要的是理解,不然用了還是容易出錯。所以下面主要寫的是一些初步理解方面的,等到用得多了就能更有經驗了。
與自動分配空間相比有下列一些區別:
-
時間不同
自動分配是編譯器默認的類型(auto自動型),自動分配空間,自動回收空間。這一過程都是在編譯時,編譯器設定好的。而動態分配程序執行時,調用malloc等函數進行分配的。 -
空間不同
我們把c語言編譯后的應用程序在內存中的占用,按地址高低順序分為以下部分:
- 棧區(stack)-存放函數的參數值,局部變量的值等。
- 堆區(heap)-由程序猿分配釋放,若程序猿不釋放,程序結束時可能由由系統自動回收 。
- 全局區(static)-存放的是全局變量和靜態變量,初始化的全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。 程序結束后由系統釋放。
- 文字常量區-常量字符串就是放在這里的。程序結束后由系統釋放。
- 代碼區-存放函數體的二進制代碼。
malloc函數分配的區域就是堆區,程序猿利用malloc函數在堆區分配一個指定大小的空間。
動態分配的好處是:自由度大,想什么時候分配就什么時候分配,分配大小也自己定,不用受編譯器和系統的太多限制。堆的空間還大。
但動態分配最致命的就是:內存泄露-指程序中動態分配的堆內存由於某種原因程序未釋放或無法釋放,造成系統內存的浪費,導致程序運行速度減慢甚至系統崩潰等嚴重后果。
自由的同時帶來了麻煩!如果把自動分配比作孩子,內存空間比作生活的開銷,系統和編譯器就是父母。父母每月給孩子固定的money,省下來的money孩子自己偷偷買皮膚,沒了父母給。而動態分配自己就是父母,只能自己替自己做主,每一筆開銷都要打量着。花完之后,一個free函數,花完的錢又回來了(要是真的就好了),不free或者free錯誤直接破產。
下面來個錯誤示范
void test1(int *p,int n)
{
p = malloc(n);
if(p == NULL)
exit(1);
}
int main()
{
int num = 100;
int *p = NULL;
test1(p,num);
free(p);
return 0;
}
結果:
結果是空,什么也沒有,也沒有報任何錯誤。多么會鑽空子的錯誤,main函數中free的p其實是main中的空指針,這兩個函數中定義的都是局部變量,有作用域限制,這很簡單的道理,但往往就會陷入這樣的陷阱。
free函數只釋放之前調用 calloc、malloc 或 realloc 所分配的內存空間,對空指針不會進行任何操作,但也不會報錯。
free后的那片空間是自由的了,任何程序都有寫入的權利。來一個野指針試試:
int main()
{
char *p = "1";
p = malloc(sizeof(int));
if(p == NULL)
{
printf("malloc() error!\n");
exit(1);
}
*p = 10;
printf("%d %p\n",*p,p);
free(p); //free完p后再對*p賦值,p就成了野指針,很危險!
//free完后最好把指針設為空指針--> p = NULL;
printf("%d %p\n",*p,p);
*p = 1;
printf("%d %p\n",*p,p);
return 0;
}
不同環境下結果可能不同,我在這打印的結果是:
10 0x5571b0f7f2a0
0 0x5571b0f7f2a0
1 0x5571b0f7f2a0
打印地址可以看出p指針在free前后指向的地址一直沒變,而free完后的空間已經不完全由此程序所支配,任何程序都可以寫入此空間。那么p就是典型的野指針,可能會篡改其他程序的信息,出現難以預料的結果,是非常危險的!
所以謹記:
* 成對使用,有一個malloc,就應該有一個free.
* 最好在同一調用層上使用這兩個函數,不要像上面的錯誤示范一樣。
* malloc分配的內存一定要初始化。free后的指針一定要設置為NULL。
以上就是初步的理解和使用。