日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

詳解C語言中的動態內存管理_C 語言

作者:小馬學習代碼 ? 更新時間: 2023-01-10 編程語言

一、動態內存管理

1.1為什么要有動態內存管理

1.1.1 ?在c語言中我們普通的內存開辟是直接在棧上進行開辟的?

int i = 20;//在棧空間上開辟四個字節
int arr[10]={0}; //在棧中連續開辟四十個字節

這樣開辟的特點是:

(1)他所開辟的空間是固定的?

(2)數組在申明的時候,必須指定數組的長度,它所需要的內存在編譯時分配

但對于空間的需求,我們有的時候并不知道,有可能空間開大了造成了浪費,也有可能空間開小了造成棧溢出,這樣我們就需要一個動態的內存管理讓我們需要多少內存的時候開辟多少。

1.2動態內存介紹

1.2.1malloc 和 free

void* ? malloc ?(size_t size);

這個函數想內存中申請一個連續的空間(是在堆中申請),并返回指向這塊空間的指針。?

如果開辟成功,則返回一個指向開辟好空間的指針。

如果開辟失敗,則返回一個NULL指針,因此malloc的返回值一定要做檢查。

返回值的類型是 void* ,所以malloc函數并不知道開辟空間的類型,具體在使用的時候使用者自己 來決定。

如果參數 size 為0,malloc的行為是標準是未定義的,取決于編譯器。

同樣的C語言提供了另外一個函數free,專門是用來做動態內存的釋放和回收的

void * free (void * ptr)?

free 是用來釋放動態開辟的內存的?

如果參數 ptr 指向的空間不是動態開辟的,那free函數的行為是未定義的。

如果參數 ptr 是NULL指針,則函數什么事都不做。

#include<stdio.h>
#include<stdlib.h>  //malloc 和free 都在stdlib.h的頭文件里
int main()
{
    int arr[10] ={0}; //這是在棧中申請連續的四十個空間 是靜態的
    int * arr1;
    int *ptr ;
    ptr =(int*)malloc (10*sizeof(int)); //申請一個動態內存空間為40字節
    if(ptr==NULL) //防止申請空間失敗傳入了空指針
    {
        perror("ptr");
    }
    arr1=ptr;
    free(arr1);  //結束后要進行一個空間的釋放
    arr1=NULL;      //然后在指向空指針防止出現了野指針
    //這就是申請一個動態內存空間的套用過程
    
    return 0;
}

1.2.2 calloc

c語言同樣的提供了一個函數calloc,也是用來動態內存的分配

void* calloc (size_t num, size_t size);

函數的功能是為 num 個大小為 size 的元素開辟一塊空間,并且把空間的每個字節初始化為0。

與函數 malloc 的區別只在于 calloc 會在返回地址之前把申請的空間的每個字節初始化為全0。

#include<stdio.h>
#include<stdlib.h>  //malloc 和free 都在stdlib.h的頭文件里
int main()
{
    int arr[10] ={0}; //這是在棧中申請連續的四十個空間 是靜態的
    int * arr1;
    int *ptr ;
    ptr =(int*)calloc (10,sizeof(int)); //申請一個動態內存空間為40字節
    if(ptr==NULL) //防止申請空間失敗傳入了空指針
    {
        perror("ptr");
    }
    arr1=ptr;
    free(arr1);  //結束后要進行一個空間的釋放
    arr1=NULL;      //然后在指向空指針防止出現了野指針
    //這就是申請一個動態內存空間的套用過程
    
    return 0;
}

1.2.3 realloc

realloc 使我們申請的的動態內存空間變得靈活,在申請動態內存空間的時候,有時候我們申請的過大,或者申請的過小的時候,我們可以通過realloc也對我們申請的空間進行一個合理的調整改變

void* realloc (void* ptr, size_t size);

  • ptr 是要調整的內存地址
  • size 調整之后新大小
  • 返回值為調整之后的內存起始位置

這個函數調整原內存空間大小的基礎上,還會將原來內存中的數據移動到 新 的空間。

這有兩種調節:

第一種是在你原來的內存上進行了一個改變(內存改變不大),就是在原有的內存空間進行加大空間。

第二種就是原有空間之后沒有足夠多的空間時,擴展的方法是:在堆空間上另找一個合適大小的連續空間來使用。這樣函數返回的是一個新的內存地址。

#include<stdio.h>
#include<stdlib.h>  //malloc 和free 都在stdlib.h的頭文件里
int main()
{
    int arr[10] ={0}; //這是在棧中申請連續的四十個空間 是靜態的
    int * arr1;
    int *ptr ;
    ptr =(int*)calloc (10,sizeof(int)); //申請一個動態內存空間為40字節
    if(ptr==NULL) //防止申請空間失敗傳入了空指針
    {
        perror("ptr");
    }
    arr1=ptr;
    arr1 =(int*)realloc (arr1,10000);  //改變原有的內存空間
    free(arr1);
    arr1=NULL;
    ptr=NULL; 
    return 0;
}

1.3常見的動態內存錯誤

1.3.1對NULL指針解引用操作

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int *ptr;
    ptr=(int*)malloc(sizeof(int));
    *ptr=1;  //這里有可能申請失敗 ,但我這沒有失敗,為了以防萬一還是需要進行判斷一下,正確的申請在上面
    free(ptr);
    ptr=NULL;
    
    
    return 0;
}

1.3.2對動態內存的越界

#include<stdio.h>
#include<stdlib.h>  //malloc 和free 都在stdlib.h的頭文件里
int main()
{
    int *ptr ;
    ptr =(int*)malloc(40); //申請一個動態內存空間為40字節
    if(ptr==NULL) //防止申請空間失敗傳入了空指針
    {
        perror("ptr");
    }
    
    for(int i=0;i<=11;i++)
    {
        *(ptr+i)=i;   //申請的是四十個字節,這里產生了越界
    }
    for(int i=0;i<=11;i++)
    {
        printf("%d ",*(ptr+i));
    }
    free(ptr);
    ptr=NULL;
    return 0;
}

1.3.3對非動態空間進行釋放

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int *p;
    *p=10;  
    free(p);  //這里的p并不是動態內存空間仍然進行了釋放
    return 0;
}

1.3.4 動態內存空間的部分釋放

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int *p=(int*)malloc(sizeof(int)*2);
    if(p==NULL)
    {
        perror("p");
    }
    p++;
    free(p); //這里的p的地址并不是起始地址,只是進行了部分的釋放
    p=NULL;
   
}

1.3.5對一塊動態內存進行多次釋放

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int *p=(int*)malloc(sizeof(int)*2);
    if(p==NULL)
    {
        perror("p");
    }
    
    free(p);
   // ~~~~~~~~~~
    free(p);  //  已經釋放p了有進行了釋放
    p=NULL;
   
}

這個真的有可能發生,當我們代碼寫的比較長的時候,我們有可能忘了我們是否已經釋放這塊空間,就有可能進行重復的釋放,這是不正確的,而解決他的方法是,當我們釋放了一塊空間后,一定讓他指為空指針。

1.3.6動態內存忘記釋放(內存泄漏)

#include<stdio.h>
#include<stdlib.h>
void test(int *p)
{
     p=(int*)malloc(sizeof(int)*2);
    if(p==NULL)
    {
        perror("p");
    }
}
int main()
{
    int *ptr;
    test(ptr); //這里就是沒有對內存進行釋放
   
}

總結:

對于動態內存還是比較重要的,因為堆的空間是比棧的空間的是大的,同時我們要知道,動態的是可以進行修改的,我們需要多少內存就可以開辟多少內存,防止了內存的浪費,但是我們在申請動態內存的時候一定要防止一些不必要的錯誤不然就會得不償失。

原文鏈接:https://blog.csdn.net/m0_63177573/article/details/128263133

欄目分類
最近更新