C語言中的內存分配與釋放


C語言中的內存分配與釋放

  對C語言一直都是抱着學習的態度,很多都不懂,今天突然被問道C語言的內存分配問題,說了一些自己知道的,但感覺回答的並不完善,所以才有這篇筆記,總結一下C語言中內存分配的主要內容。

相關問題 

  剛剛在一篇博文看到一個簡單的問題:

復制代碼
//code1
char* toStr() 
{
    char *s = "abcdefghijkl";
    return s;
}
int main()
{
    cout << toStr() << endl;
    return 0;
}

//code2
char* toStr() 
{
    char s[] = "abcdefghijkl";
    return s;
}
int main()
{
    cout << toStr() << endl;
    return 0;
}
復制代碼

  兩段代碼都很簡單,輸出一段字符,類型不同,一個是char*字符串,一個是char[]數據。

  結果你知道嗎? 這個我確實知道,相信大部分人也都回知道,必然有一個不好使,或者兩個都不好使!!!都對就沒意思了~

  結果:第一個正確輸出,第二個輸出亂碼。

  原因:在於局部變量的作用域和內存分配的問題,第一char*是指向一個常量,作用域為函數內部,被分配在程序的常量區,直到整個程序結束才被銷毀,所以在程序結束前常量還是存在的。而第二個是數組存放的,作用域為函數內部,被分配在棧中,就會在函數調用結束后被釋放掉,這時你再調用,肯定就錯誤了。

內存分配

  什么是局部變量、全局變量和靜態變量?

  顧名思義,局部變量就是在一個有限的范圍內的變量,作用域是有限的,對於程序來說,在一個函數體內部聲明的普通變量都是局部變量,局部變量會在棧上申請空間,函數結束后,申請的空間會自動釋放。而全局變量是在函數體外申請的,會被存放在全局(靜態區)上,知道程序結束后才會被結束,這樣它的作用域就是整個程序。靜態變量和全局變量的存儲方式相同,在函數體內聲明為static就可以使此變量像全局變量一樣使用,不用擔心函數結束而被釋放。

相關函數:

復制代碼
void *malloc(size_t size);
void free(void *p);

/*一般這樣用
Struct elem *p;
p = (struct elem*)malloc(sizeof(struct elem))

void free(p)
*/
復制代碼

malloc原理

  malloc函數的實質體現在,它有一個將可用的內存塊連接為一個長長的列表的所謂空閑鏈表。調用malloc函數時,它沿連接表尋找一個大到足以滿足用戶請求所需要的內存塊。然后,將該內存塊一分為二(一塊的大小與用戶請求的大小相等,另一塊的大小就是剩下的字節)。接下來,將分配給用戶的那塊內存傳給用戶,並將剩下的那塊(如果有的話)返回到連接表上。調用free函數時,它將用戶釋放的內存塊連接到空閑鏈上。到最后,空閑鏈會被切成很多的小內存片段,如果這時用戶申請一個大的內存片段,那么空閑鏈上可能沒有可以滿足用戶要求的片段了。於是,malloc函數請求延時,並開始在空閑鏈上翻箱倒櫃地檢查各內存片段,對它們進行整理,將相鄰的小空閑塊合並成較大的內存塊。如果無法獲得符合要求的內存塊,malloc函數會返回NULL指針,因此在調用malloc動態申請內存塊時,一定要進行返回值的判斷。

分類:

  • 棧區(stack)—由編譯器自動分配釋放,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。
  • 堆區(heap)—一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表
  • 全局區(靜態區)(static)—全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態                                  變量在相鄰的另一塊區域。  程序結束后由系統釋放。
  • 常量區—常量字符串就是放在這里的,直到程序結束后由系統釋放。上面的問題就在這里!!!
  • 代碼區—存放函數體的二進制代碼。

直接搬運的代碼,確實很好!!容易理解

復制代碼
//main.cpp    
int a = 0; //全局初始化區
char *p1; //全局未初始化區
    
main()
{
    int b; //棧
    char s[] = "abc"; //棧
    char *p2; //棧
    char *p3 = "123456"; //123456\\0在常量區,p3在棧上。
    static int c =0;//全局(靜態)初始化區
    p1 = (char *)malloc(10);    
    p2 = (char *)malloc(20);//分配得來得10和20字節的區域就在堆區。
    strcpy(p1, "123456"); //123456\\0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。        
} 
復制代碼

此外,還有realloc(重新分配內存)、calloc(初始化為0)、alloca(在棧上申請內存,自動釋放)等。

知識共享許可協議
本文 由 cococo點點 創作,采用 知識共享 署名-非商業性使用-相同方式共享 3.0 中國大陸 許可協議進行許可。歡迎轉載,請注明出處:
轉載自:cococo點點 htt


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM