詳解C語言中的動態(tài)內(nèi)存管理
一、動態(tài)內(nèi)存管理
1.1為什么要有動態(tài)內(nèi)存管理
1.1.1 在c語言中我們普通的內(nèi)存開辟是直接在棧上進(jìn)行開辟的
int i = 20;//在??臻g上開辟四個字節(jié) int arr[10]={0}; //在棧中連續(xù)開辟四十個字節(jié)
這樣開辟的特點(diǎn)是:
(1)他所開辟的空間是固定的
(2)數(shù)組在申明的時候,必須指定數(shù)組的長度,它所需要的內(nèi)存在編譯時分配
但對于空間的需求,我們有的時候并不知道,有可能空間開大了造成了浪費(fèi),也有可能空間開小了造成棧溢出,這樣我們就需要一個動態(tài)的內(nèi)存管理讓我們需要多少內(nèi)存的時候開辟多少。
1.2動態(tài)內(nèi)存介紹
1.2.1malloc 和 free
void* malloc (size_t size);
這個函數(shù)想內(nèi)存中申請一個連續(xù)的空間(是在堆中申請),并返回指向這塊空間的指針。
如果開辟成功,則返回一個指向開辟好空間的指針。
如果開辟失敗,則返回一個NULL指針,因此malloc的返回值一定要做檢查。
返回值的類型是 void* ,所以malloc函數(shù)并不知道開辟空間的類型,具體在使用的時候使用者自己 來決定。
如果參數(shù) size 為0,malloc的行為是標(biāo)準(zhǔn)是未定義的,取決于編譯器。
同樣的C語言提供了另外一個函數(shù)free,專門是用來做動態(tài)內(nèi)存的釋放和回收的
void * free (void * ptr)
free 是用來釋放動態(tài)開辟的內(nèi)存的
如果參數(shù) ptr 指向的空間不是動態(tài)開辟的,那free函數(shù)的行為是未定義的。
如果參數(shù) ptr 是NULL指針,則函數(shù)什么事都不做。
#include<stdio.h> #include<stdlib.h> //malloc 和free 都在stdlib.h的頭文件里 int main() { int arr[10] ={0}; //這是在棧中申請連續(xù)的四十個空間 是靜態(tài)的 int * arr1; int *ptr ; ptr =(int*)malloc (10*sizeof(int)); //申請一個動態(tài)內(nèi)存空間為40字節(jié) if(ptr==NULL) //防止申請空間失敗傳入了空指針 { perror("ptr"); } arr1=ptr; free(arr1); //結(jié)束后要進(jìn)行一個空間的釋放 arr1=NULL; //然后在指向空指針防止出現(xiàn)了野指針 //這就是申請一個動態(tài)內(nèi)存空間的套用過程 return 0; }
1.2.2 calloc
c語言同樣的提供了一個函數(shù)calloc,也是用來動態(tài)內(nèi)存的分配
void* calloc (size_t num, size_t size);
函數(shù)的功能是為 num 個大小為 size 的元素開辟一塊空間,并且把空間的每個字節(jié)初始化為0。
與函數(shù) malloc 的區(qū)別只在于 calloc 會在返回地址之前把申請的空間的每個字節(jié)初始化為全0。
#include<stdio.h> #include<stdlib.h> //malloc 和free 都在stdlib.h的頭文件里 int main() { int arr[10] ={0}; //這是在棧中申請連續(xù)的四十個空間 是靜態(tài)的 int * arr1; int *ptr ; ptr =(int*)calloc (10,sizeof(int)); //申請一個動態(tài)內(nèi)存空間為40字節(jié) if(ptr==NULL) //防止申請空間失敗傳入了空指針 { perror("ptr"); } arr1=ptr; free(arr1); //結(jié)束后要進(jìn)行一個空間的釋放 arr1=NULL; //然后在指向空指針防止出現(xiàn)了野指針 //這就是申請一個動態(tài)內(nèi)存空間的套用過程 return 0; }
1.2.3 realloc
realloc 使我們申請的的動態(tài)內(nèi)存空間變得靈活,在申請動態(tài)內(nèi)存空間的時候,有時候我們申請的過大,或者申請的過小的時候,我們可以通過realloc也對我們申請的空間進(jìn)行一個合理的調(diào)整改變
void* realloc (void* ptr, size_t size);
- ptr 是要調(diào)整的內(nèi)存地址
- size 調(diào)整之后新大小
- 返回值為調(diào)整之后的內(nèi)存起始位置
這個函數(shù)調(diào)整原內(nèi)存空間大小的基礎(chǔ)上,還會將原來內(nèi)存中的數(shù)據(jù)移動到 新 的空間。
這有兩種調(diào)節(jié):
第一種是在你原來的內(nèi)存上進(jìn)行了一個改變(內(nèi)存改變不大),就是在原有的內(nèi)存空間進(jìn)行加大空間。
第二種就是原有空間之后沒有足夠多的空間時,擴(kuò)展的方法是:在堆空間上另找一個合適大小的連續(xù)空間來使用。這樣函數(shù)返回的是一個新的內(nèi)存地址。
#include<stdio.h> #include<stdlib.h> //malloc 和free 都在stdlib.h的頭文件里 int main() { int arr[10] ={0}; //這是在棧中申請連續(xù)的四十個空間 是靜態(tài)的 int * arr1; int *ptr ; ptr =(int*)calloc (10,sizeof(int)); //申請一個動態(tài)內(nèi)存空間為40字節(jié) if(ptr==NULL) //防止申請空間失敗傳入了空指針 { perror("ptr"); } arr1=ptr; arr1 =(int*)realloc (arr1,10000); //改變原有的內(nèi)存空間 free(arr1); arr1=NULL; ptr=NULL; return 0; }
1.3常見的動態(tài)內(nèi)存錯誤
1.3.1對NULL指針解引用操作
#include<stdio.h> #include<stdlib.h> int main() { int *ptr; ptr=(int*)malloc(sizeof(int)); *ptr=1; //這里有可能申請失敗 ,但我這沒有失敗,為了以防萬一還是需要進(jìn)行判斷一下,正確的申請?jiān)谏厦? free(ptr); ptr=NULL; return 0; }
1.3.2對動態(tài)內(nèi)存的越界
#include<stdio.h> #include<stdlib.h> //malloc 和free 都在stdlib.h的頭文件里 int main() { int *ptr ; ptr =(int*)malloc(40); //申請一個動態(tài)內(nèi)存空間為40字節(jié) if(ptr==NULL) //防止申請空間失敗傳入了空指針 { perror("ptr"); } for(int i=0;i<=11;i++) { *(ptr+i)=i; //申請的是四十個字節(jié),這里產(chǎn)生了越界 } for(int i=0;i<=11;i++) { printf("%d ",*(ptr+i)); } free(ptr); ptr=NULL; return 0; }
1.3.3對非動態(tài)空間進(jìn)行釋放
#include<stdio.h> #include<stdlib.h> int main() { int *p; *p=10; free(p); //這里的p并不是動態(tài)內(nèi)存空間仍然進(jìn)行了釋放 return 0; }
1.3.4 動態(tài)內(nèi)存空間的部分釋放
#include<stdio.h> #include<stdlib.h> int main() { int *p=(int*)malloc(sizeof(int)*2); if(p==NULL) { perror("p"); } p++; free(p); //這里的p的地址并不是起始地址,只是進(jìn)行了部分的釋放 p=NULL; }
1.3.5對一塊動態(tài)內(nèi)存進(jìn)行多次釋放
#include<stdio.h> #include<stdlib.h> int main() { int *p=(int*)malloc(sizeof(int)*2); if(p==NULL) { perror("p"); } free(p); // ~~~~~~~~~~ free(p); // 已經(jīng)釋放p了有進(jìn)行了釋放 p=NULL; }
這個真的有可能發(fā)生,當(dāng)我們代碼寫的比較長的時候,我們有可能忘了我們是否已經(jīng)釋放這塊空間,就有可能進(jìn)行重復(fù)的釋放,這是不正確的,而解決他的方法是,當(dāng)我們釋放了一塊空間后,一定讓他指為空指針。
1.3.6動態(tài)內(nèi)存忘記釋放(內(nèi)存泄漏)
#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); //這里就是沒有對內(nèi)存進(jìn)行釋放 }
總結(jié):
對于動態(tài)內(nèi)存還是比較重要的,因?yàn)槎训目臻g是比棧的空間的是大的,同時我們要知道,動態(tài)的是可以進(jìn)行修改的,我們需要多少內(nèi)存就可以開辟多少內(nèi)存,防止了內(nèi)存的浪費(fèi),但是我們在申請動態(tài)內(nèi)存的時候一定要防止一些不必要的錯誤不然就會得不償失。
以上就是詳解C語言中的動態(tài)內(nèi)存管理的詳細(xì)內(nèi)容,更多關(guān)于C語言動態(tài)內(nèi)存管理的資料請關(guān)注腳本之家其它相關(guān)文章!
- 深入了解C語言的動態(tài)內(nèi)存管理
- 詳解C語言中動態(tài)內(nèi)存管理及柔性數(shù)組的使用
- C語言動態(tài)內(nèi)存的分配最全面分析
- 一文帶你搞懂C語言動態(tài)內(nèi)存管理
- C語言動態(tài)內(nèi)存分配圖文講解
- 使用c語言輕松實(shí)現(xiàn)動態(tài)內(nèi)存管
- 一文帶你了解C語言中的動態(tài)內(nèi)存管理函數(shù)
- C語言動態(tài)內(nèi)存管理的原理及實(shí)現(xiàn)方法
- 詳解C語言中動態(tài)內(nèi)存管理
- C語言中常見的六種動態(tài)內(nèi)存錯誤總結(jié)
- 一文解析C語言中動態(tài)內(nèi)存管理
- C語言動態(tài)內(nèi)存管理的實(shí)現(xiàn)示例
相關(guān)文章
C++ Qt開發(fā)之使用QProcess實(shí)現(xiàn)進(jìn)程管理
Qt 是一個跨平臺C++圖形界面開發(fā)庫,利用Qt可以快速開發(fā)跨平臺窗體應(yīng)用程序,本文將重點(diǎn)介紹如何運(yùn)用QProcess組件實(shí)現(xiàn)針對進(jìn)程的控制管理等,感興趣的可以了解下2024-03-03詳解C++中的內(nèi)存同步模式(memory order)
這篇文章主要介紹了C++中的內(nèi)存同步模式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04c語言中malloc、realloc與calloc 的區(qū)別以及聯(lián)系
以下是對c語言中的malloc函數(shù),realloc函數(shù)與calloc函數(shù)的區(qū)別以及它們之間的聯(lián)系進(jìn)行了介紹,需要的朋友可以過來參考下2013-08-08二進(jìn)制、八進(jìn)制?、十進(jìn)制、十六進(jìn)制之間轉(zhuǎn)換的原理詳解
本文介紹了進(jìn)制的概念及其在C語言編程中的應(yīng)用,進(jìn)制是進(jìn)位制的簡稱,描述了數(shù)值在不同進(jìn)制下的表示方法,常見的進(jìn)制包括二進(jìn)制、八進(jìn)制和十六進(jìn)制,二進(jìn)制使用0和1表示,八進(jìn)制使用0-7數(shù)字表示,十六進(jìn)制使用0-9和A-F表示,文章還介紹了如何在不同進(jìn)制之間進(jìn)行轉(zhuǎn)換2024-11-11如何使用arm-none-eabi-gcc編譯器搭建STM32的Vscode開發(fā)環(huán)境
這篇文章主要介紹了使用arm-none-eabi-gcc編譯器搭建STM32的Vscode開發(fā)環(huán)境,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07C++右值引用與移動構(gòu)造函數(shù)基礎(chǔ)與應(yīng)用詳解
左值和右值都是針對表達(dá)式,左值是指表達(dá)式結(jié)束后依然存在的持久對象,右值是指表達(dá)式結(jié)束時就不再存在的臨時對象,下面這篇文章主要給大家介紹了關(guān)于C++11右值引用和移動語義的相關(guān)資料,需要的朋友可以參考下2023-02-02