1. 程式人生 > >C 語言動態記憶體

C 語言動態記憶體

文章目錄

說明

主要參考以下部落格:

記憶體示意圖


示意圖1:
記憶體示意圖

示意圖2:

在這裡插入圖片描述

alloc()


參考部落格:

https://blog.csdn.net/wula_heixiu/article/details/79410595**

該函式是在棧上分配記憶體!

這是一個不完善的儲存分配程式,由兩個函式組成。alloc(n)返回一個指向連續字元儲存單元的指標,alloc函式的呼叫者可利用該指標儲存字元序列。afree§釋放已分配的儲存空間,以便以後重用。

之所以說“不完善”,是因為對afree函式的呼叫次序必須與alloc函式的次序相反。換句話說,alloc與afree以棧的方式(即後進先出的列表)進行儲存空間的管理。標準庫中提供了具有類似功能的函式malloc和free,它們沒有上述限制。

最容易的實現方法是讓alloc函式對一個大字元陣列allcbuf中的空間進行分配。該陣列是alloc和afree兩個函式的私有陣列。由於函式alloc和afree處理的物件是指標而不是陣列下標,因此,其他函式無需知道該陣列的名字,將其宣告為static型別。

實際實現時,該陣列甚至沒有名字,它可以通過malloc函式或像作業系統申請一個指向無名儲存塊的指標獲得。(不懂)

alloc函式具體實現:我們使用指標allocp指向allocbuf中的下一個空閒單元。當呼叫alloc申請n個字元的儲存空間時,alloc檢查allocbuf中有沒有足夠的剩餘空間。如果有,則返回allocp的當前值(即空閒塊開始的位置),然後將allocp加n以使它指向下一個空閒區域。如果沒有,則返回0。

afree函式具體實現:如果p在allocbuf的邊界之內,則afree§僅僅只是將allocp的值設定為p。

#define ALLOCSIZE 1000   /* 可用空間大小 */
static char allocbuf[ALLOCSIZE]; /* alloc使用的儲存區 */ static char *allocp; /* 下一個空閒位置 */ char *alloc(int n) /* 返回指向n個字元的指標 */ { if(allocbuf + ALLOCSIZE - allocp >= n){ /* 有足夠的空間 */ allocp += n; return allocp - n; /* 分配前的指標 */ } else /* 空閒空間不夠 */ return 0; } void afree(char *p) /* 釋放p指向的儲存區 */ { if(p >= allocbuf && p < allocbuf + ALLOCSIZE) allocp = p; }

malloc()


標頭檔案:#include “malloc.h”

函式原型:void *malloc(size_t size)

功能: 從空閒記憶體池中分配連續記憶體,但不初始化

引數: 申請變數位元組數的整數倍

返回: 若分配成功則返回一個指向該記憶體塊的指標,在使用時可根據需要做強制型別轉換,否則返回NULL(空指標)//需要判空,最後要 free,釋放記憶體空間給系統,

注意: free 函式與 malloc 函式是成對出現的,申請malloc的時候儘量去給它進行一下初始化,防止後面出現一些不確定性的東西;

生命週期: 只要沒有呼叫 free 這個函式,程序沒有結束,那麼此時,這個函式的生命週期就會一直存在在記憶體中;它是存放在堆空間中的,它不會因為你去函式呼叫的結束自動去釋放(堆當中的記憶體是全域性的)

擴充套件部落格:memset()函式及其作用

calloc()


標頭檔案: #include “stdlib.h ”

函式原型: void *colloc(size_t num_elements,size_t element_size);

功能: 從空閒記憶體池中分配連續記憶體,但初始化

引數: :num_elements 是所需的元素的數量,element_size 是每個元素的位元組數

其他同上

realloc()


標頭檔案:#include “malloc.h”

函式原型: void *realloc(void *ptr,size_t new_size);

功能: 在指標 ptr 指向的記憶體基礎上擴大或者縮小記憶體

注意:

  • 引數 ptr 是指向先前通過 malloc, calloc 和 realloc 函式後分配的記憶體塊的指標,new_size 是記憶體塊的新尺寸,可能大於或者小於原有記憶體尺寸;因此,realloc在 C語言中也被稱為動態陣列
  • 當擴充套件記憶體的時候,不會對新增進記憶體塊的位元組進行初始化
  • 若不能調整記憶體則返回NULL,但原有記憶體中的資料是不會發生改變的
  • 若第一個引數為NULL那麼功能 等同與 malloc 函式,若第二個引數為 0 ,那麼會釋放呼叫記憶體塊

free()


  • free之後如果還有這塊記憶體地址的話,此時這塊記憶體歸還給了系統(可能這塊記憶體還處於一個空閒狀態,裡面的值短暫的會保留),但是還是可以對其進行操作。
  • 因此 free 之後,申請記憶體的那個指標就會變成野指標
  • 所以儘量在操作之後:將指標置為NULL

常見錯誤程式碼例項


參考部落格:經典筆試題:動態記憶體分配,詳解

  1. 情景一
void fun(char *p)
{
    p = (char *)malloc(100);
}

int main()
{
    char *str = NULL;
    fun(str);
    strcpy(str,"hello world");

    system("pause");
    return 0;
}

錯誤原因:錯在這裡的傳參發生了拷貝行為,並不是傳的地址

  1. 情景二
char *fun(void)
{
    char p[] = "hello world";
    return p;
}

int main()
{
    char *str = NULL;
    str = fun();
    printf("%s\n",str);

    system("pause");
    return 0;
}

錯誤原因:不會打印出Hello world,也不會造成記憶體洩漏,而是會打印出隨機值。因為申請在記憶體在棧上而不是在堆上

  1. 情景三
void fun(char **p,int num)
{
    *p = (char *)malloc(num);
}

int main()
{
    char *str = NULL;
    fun(&str,100);
    strcpy(str, "hello");;
    printf("%s\n",str);

    system("pause");
    return 0;
}

錯誤原因:記憶體洩漏

  1. 情景四
int main()
{
    char *str = (char *)malloc(100);
    strcpy(str,"hello");
    free(str);
    if (str!=NULL)
    {
        strcpy(str,"world");
        printf("%s\n",str);
    }
    return 0;
}

錯誤原因:free 後變成野指標,此時的訪問是一種 undefined behavior,程式會 crash