一、malloc()和free()的基本概念以及基本用法:
1、函數原型及說明:
void *malloc(long NumBytes):該函數分配了NumBytes個字節,並返回了指向這塊內存的指針。如果分配失敗,則返回一個空指針(NULL)。
關於分配失敗的原因,應該有多種,比如說空間不足就是一種。
void free(void *FirstByte): 該函數是將之前用malloc分配的空間還給程序或者是操作系統,也就是釋放了這塊內存,讓它重新得到自由。
2、函數的用法:
其實這兩個函數用起來倒不是很難,也就是malloc()之后覺得用夠了就甩了它把它給free()了,舉個簡單例子:
程序代碼:
// Code...
char *Ptr = NULL;
Ptr = (char *)malloc(100 * sizeof(char));
if (NULL == Ptr)
{
exit (1);
}
gets(Ptr);
// code...
free(Ptr);
Ptr = NULL;
// code...
就是這樣!當然,具體情況要具體分析以及具體解決。比如說,你定義了一個指針,在一個函數里申請了一塊內存然后通過函數返回傳遞給這個指針,那么也許釋放這塊內存這項工作就應該留給其他函數了。
3、關於函數使用需要注意的一些地方:
A、申請了內存空間后,必須檢查是否分配成功。
B、當不需要再使用申請的內存時,記得釋放;釋放后應該把指向這塊內存的指針指向NULL,防止程序后面不小心使用了它。
C、這兩個函數應該是配對。如果申請后不釋放就是內存泄露;如果無故釋放那就是什么也沒有做。釋放只能一次,如果釋放兩次及兩次以上會
出現錯誤(釋放空指針例外,釋放空指針其實也等於啥也沒做,所以釋放空指針釋放多少次都沒有問題)。
D、雖然malloc()函數的類型是(void *),任何類型的指針都可以轉換成(void *),但是最好還是在前面進行強制類型轉換,因為這樣可以躲過一些編譯器的檢查。
好了!最基礎的東西大概這么說!現在進入第二部分:
二、malloc()到底從哪里得來了內存空間:
1、malloc()到底從哪里得到了內存空間?
答案是從堆里面獲得空間。也就是說函數返回的指針是指向堆里面的一塊內存。操作系統中有一個記錄空閑內存地址的鏈表。當操作系統收到程序的申請時,就會遍歷該鏈表,然后就尋找第一個空間大於所申請空間的堆結點,然后就將該結點從空閑結點鏈表中刪除,並將該結點的空間分配給程序。就是這樣!
說到這里,不得不另外插入一個小話題,相信大家也知道是什么話題了。什么是堆?說到堆,又忍不住說到了棧!什么是棧?下面就另外開個小部分專門而又簡單地說一下這個題外話:
2、什么是堆:
堆是大家共有的空間,分全局堆和局部堆。全局堆就是所有沒有分配的空間,局部堆就是用戶分配的空間。堆在操作系統對進程 初始化的時候分配,運行過程中也可以向系統要額外的堆,但是記得用完了要還給操作系統,要不然就是內存泄漏。
什么是棧:棧是線程獨有的,保存其運行狀態和局部自動變量的。棧在線程開始的時候初始化,每個線程的棧互相獨立。每個函數都有自己的棧,棧被用來在函數之間傳遞參數。操作系統在切換線程的時候會自動的切換棧,就是切換SS/ESP寄存器。棧空間不需要在高級語言里面顯式的分配和釋放。
以上的概念描述是標准的描述,不過有個別語句被我刪除,不知道因為這樣而變得不標准了^_^.
通過上面對概念的描述,可以知道:
棧是由編譯器自動分配釋放,存放函數的參數值、局部變量的值等。操作方式類似於數據結構中的棧。
堆一般由程序員分配釋放,若不釋放,程序結束時可能由OS回收。注意這里說是可能,並非一定。所以我想再強調一次,記得要釋放!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3、c 什么時候用malloc 分配內存?
1。對所需內存的是大小在編譯的時候不能確定的時候。
2。如果你不想把你的對象放在棧上,而想把他放在堆上。
3。當你的對象在只有在運行才能確定是否要是否要開辟空間的時候。
一般在一些數據結構里經常有用到,但是用這個的好處就是不會浪費空間。
malloc()是申請空間的函數。舉個例子:對於數組,如:int array[20],我們一開始就申請了20個int 空間,所以無需用malloc()。而對於link,每個linknode都是在鏈上去的時候才malloc()的。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
描述內存分配方式以及它們的區別?
1) 從靜態存儲區域分配。內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間都存在。例如全局變量,static 變量。
2) 在棧上創建。在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置於處理器的指令集。
3) 從堆上分配,亦稱動態內存分配。程序在運行的時候用malloc 或new 申請任意多少的內存,程序員自己負責在何時用free 或delete 釋放內存。動態內存的生存期由程序員決定,使用非常靈活,但問題也最多。
例如我們定義一個float型數組:float score[100];
但是,在使用數組的時候,總有一個問題困擾着我們:數組應該有多大?在很多的情況下,你並不能確定要使用多大的數組,比如上例,你可能並不知道我們要定義的這個數組到底有多大,那么你就要把數組定義得足夠大。這樣,你的程序在運行時就申請了固定大小的你認為足夠大的內存空間。即使你知道你想利用的空間大小,但是如果因為某種特殊原因空間利用的大小有增加或者減少,你又必須重新去修改程序,擴大數組的存儲范圍。這種分配固定大小的內存分配方法稱之為靜態內存分配。但是這種內存分配的方法存在比較嚴重的缺陷,特別是處理某些問題時:在大多數情況下會浪費大量的內存空間,在少數情況下,當你定義的數組不夠大時,可能引起下標越界錯誤,甚至導致嚴重后果。
我們用動態內存分配就可以解決上面的問題. 所謂動態內存分配就是指在程序執行的過程中動態地分配或者回收存儲空間的分配內存的方法。動態內存分配不象數組等靜態內存分配方法那樣需要預先分配存儲空間,而是由系統根據程序的需要即時分配,且分配的大小就是程序要求的大小。從以上動、靜態內存分配比較可以知道動態內存分配相對於景泰內存分配的特點:
1、不需要預先分配存儲空間;
2、分配的空間可以根據程序的需要擴大或縮小。
要實現根據程序的需要動態分配存儲空間,就必須用到malloc函數.
malloc函數的原型為:void *malloc (unsigned int size) 其作用是在內存的動態存儲區中分配一個長度為size的連續空間。其參數是一個無符號整形數,返回值是一個指向所分配的連續存儲域的起始地址的指針。還有一點必須注意的是,當函數未能成功分配存儲空間(如內存不足)就會返回一個NULL指針。所以在調用該函數時應該檢測返回值是否為NULL並執行相應的操作。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <stdio.h>
char *returnStr()
{
char *p="hello world!";
return p;
}
int main()
{
char *str;
str=returnStr();
printf("%s/n", str);
return 0;
}
#include <stdio.h>
char *returnStr()
{
char p[]="hello world!";
return p;
}
int main()
{
char *str;
str=returnStr();
printf("%s/n", str);
return 0;
}
想問下 這倆個函數中的p是不是都是函數的局部變量?
如果都是局部變量的話,那么他們應該都是“棧”上分配內存的啊。當函數結束的時候,都會被pop出來而銷毀的。
答:
第1個,p是局部變量,但其指向的內存是全局的。函數返回后,雖然p本身銷毀了,但它指向的內存仍存在,故不會有問題
第2個,數組p是局部的,返回后,數組內存被銷毀,故有問題。
注意:第1個里面,字符串常量是占用全局內存(跟全局變量一樣),其空間是程序加載時就分配了的(雖然在源代碼中是出現在函數內部)。
第2個中,p是函數運行時臨時在棧上分配的數組。
動態分配的內存一直存在直到free,而相對應的變量(既使是指向動態分配內存)則根據其定義的位置而作用域不同。