詳細(xì)談?wù)凜語(yǔ)言中動(dòng)態(tài)內(nèi)存
前言
關(guān)于動(dòng)態(tài)內(nèi)存管理,可能有學(xué)習(xí)過的小伙伴,也有沒有聽說過的。沒有聽說過的小伙伴會(huì)覺得很奇怪啊,為什么要?jiǎng)討B(tài)開辟內(nèi)存,內(nèi)存怎么還能是動(dòng)態(tài)的。給不知道的小伙伴解釋一下。咱們平時(shí)在內(nèi)存開辟空間也就是在棧區(qū)(局部變量,函數(shù)參數(shù)等等),靜態(tài)區(qū)(全局變量,static修飾的局部變量等等)開辟空間。只能是用多少開辟多少,是非常局限的。有時(shí)候我們需要的空間大小在程序運(yùn)行的時(shí)候才能知道,那數(shù)組的編譯時(shí)開辟空間的方式就不能滿足了,所以就試試動(dòng)態(tài)內(nèi)存存儲(chǔ)。而動(dòng)態(tài)內(nèi)存開辟的空間都是在內(nèi)存中的堆空間的。
1.關(guān)于動(dòng)態(tài)內(nèi)存的函數(shù)
1.1 malloc和free函數(shù)
malloc這個(gè)函數(shù)向內(nèi)存申請(qǐng)一塊連續(xù)可用的空間,并返回指向這塊空間的指針,如果開辟成功,則返回一個(gè)指向開辟好空間的指針;如果開辟失敗,則返回一個(gè)NULL指針,因此malloc的返回值一定要做檢查。
free函數(shù)專門是用來做動(dòng)態(tài)內(nèi)存的釋放和回收的。如果參數(shù) ptr 指向的空間不是動(dòng)態(tài)開辟的,那free函數(shù)的行為是未定義的;如果參數(shù) ptr 是NULL指針,則函數(shù)什么事都不做。
說明:
該函數(shù)設(shè)計(jì)的巧妙的一點(diǎn)就是返回值為void*,因?yàn)楹瘮?shù)創(chuàng)造者并不知道使用者是想以什么樣的類型指針來接收動(dòng)態(tài)開辟的空間,所以使用者在使用時(shí)只需要強(qiáng)行轉(zhuǎn)換成自己想要的類型就可以:
int* p = (int*)malloc(40);//假設(shè)是整型時(shí)的例子
在使用完動(dòng)態(tài)開辟的空間后記得要用free函數(shù)向操作系統(tǒng)釋放開辟的空間,并且將指針賦為空指針:
int* p = (int*)malloc(40); //...... free(p);//避免內(nèi)存泄漏 p = NULL;//原指針指向的位置既然已經(jīng)還給操作系統(tǒng)的,就將指針賦為空指針,避免野指針等問題
如果參數(shù) size 為0,malloc的行為是標(biāo)準(zhǔn)是未定義的,取決于編譯器。
需要引頭文件stdlib.h
1.2 calloc函數(shù)
calloc可與malloc函數(shù)相對(duì)照來學(xué)習(xí),calloc函數(shù)的功能是為 num 個(gè)大小為 size 的元素開辟一塊空間,并且把空間的每個(gè)字節(jié)初始化為0。與malloc有兩點(diǎn)不同:
參數(shù)不同,calloc需要指明開辟空間的數(shù)據(jù)類型和該類型數(shù)據(jù)的個(gè)數(shù),而malloc是全部字節(jié)數(shù);
calloc在開辟空間的同時(shí)將空間內(nèi)的全部字節(jié)初始化為0.
1.3 realloc函數(shù)
realloc函數(shù)用來調(diào)整開辟空間的大小,有時(shí)可能開辟的空間小了,有時(shí)候可能開辟的大了,都可以通過realloc函數(shù)來修改,并且會(huì)將原來內(nèi)存中的數(shù)據(jù)移動(dòng)到新的空間。
realloc在調(diào)整空間大小時(shí)有兩種情況:
原有空間后有足夠大的空間,這種情況下擴(kuò)展內(nèi)存就直接原有內(nèi)存之后直接追加空間,原來空間的數(shù)據(jù)不發(fā)生變化,返回值為原來位置的指針;
2.原有空間后沒有足夠大的空間,這時(shí)便在堆空間找到大小合適的連續(xù)空間使用,并將原有空間的數(shù)據(jù)轉(zhuǎn)移到新的空間返回值為新空間的地址。
int main() { int *str = (int*)malloc(10); if(str != NULL) { //..... } else { exit(EXIT_FAILURE); } //擴(kuò)展容量 //代碼1 str = (int*)realloc(str, 1000);//這樣可以嗎?(如果申請(qǐng)失敗會(huì)返回一個(gè)空指針?。。? //修改代碼2 int*p = NULL; p = realloc(str, 1000); if(p != NULL) { str = p; } //... free(str); return 0; }
2.常見的動(dòng)態(tài)內(nèi)存錯(cuò)誤
2.1 對(duì)NULL指針解引用
int* p = (int*)malloc(40); *p=10; free(p);
這就是忽略了返回值可能是空指針的可能,如果開辟失敗會(huì)返回空指針。所以最好的做法就是判斷一下指針是否為空,然后再進(jìn)行下一步。
int* p = (int*)malloc(40); if(p != NULL) { *p=10; } free(p);
2.2 對(duì)動(dòng)態(tài)內(nèi)存開辟的空間越界訪問
就類似于使用數(shù)組時(shí)對(duì)數(shù)組越界訪問。
int i = 0; int *p = (int *)malloc(10*sizeof(int)); if(NULL == p) { exit(EXIT_FAILURE); } for(i=0; i<=10; i++) { *(p+i) = i;//當(dāng)i是10的時(shí)候越界訪問 } free(p);
2.3 對(duì)非動(dòng)態(tài)開辟內(nèi)存使用free釋放
int a = 0; int* p = &a; free(p);
通過查閱MSDN可以發(fā)現(xiàn):Attempting to free an invalid pointer (a pointer to a memory block that was not allocated by calloc, malloc, or realloc) may affect subsequent allocation requests and cause errors. 就是說如果用free釋放非calloc,malloc,realloc函數(shù)動(dòng)態(tài)開辟的空間可能會(huì)導(dǎo)致后續(xù)的分配請(qǐng)求并且導(dǎo)致錯(cuò)誤。
2.4 使用free釋放一塊動(dòng)態(tài)開辟內(nèi)存的一部分
int *p = (int *)malloc(100); p++; free(p);//p不再指向動(dòng)態(tài)內(nèi)存的起始位置
會(huì)導(dǎo)致動(dòng)態(tài)開辟的空間無(wú)法完全釋放,進(jìn)而可能會(huì)導(dǎo)致內(nèi)存泄漏。
2.5 對(duì)同一塊動(dòng)態(tài)內(nèi)存多次釋放
int *p = (int *)malloc(10); free(p); free(p);//重復(fù)釋放
2.6 內(nèi)存泄漏
void test() { int *p = (int *)malloc(100); if(NULL != p) { *p = 20; } } int main() { test(); return 0; }
如果使用完動(dòng)態(tài)內(nèi)存又不釋放則會(huì)導(dǎo)致這塊內(nèi)存無(wú)法在后續(xù)被利用,導(dǎo)致內(nèi)存泄漏。動(dòng)態(tài)開辟的空間一定要釋放,并且正確釋放。
補(bǔ)充:為什么要引入動(dòng)態(tài)內(nèi)存分配
1.指針只能指向一個(gè)確切的內(nèi)存空間,欲使用一個(gè)數(shù)據(jù),必須先設(shè)定一個(gè)變量來保存它么?
2.在程序設(shè)計(jì)時(shí),數(shù)據(jù)多為動(dòng)態(tài)的。即程序運(yùn)行時(shí)數(shù)據(jù)項(xiàng)的數(shù)量是變化的。
3.用數(shù)組保存多個(gè)元素時(shí),很難預(yù)知實(shí)際運(yùn)行時(shí)存儲(chǔ)的元素個(gè)數(shù),往往會(huì)導(dǎo)致預(yù)定義的元素個(gè)數(shù)不足或過多
例如:電話簿的管理程序。當(dāng)添加新聯(lián)系人時(shí),數(shù)據(jù)項(xiàng)將增加;刪除聯(lián)系人時(shí),數(shù)據(jù)項(xiàng)將減少。
動(dòng)態(tài)數(shù)據(jù)結(jié)構(gòu)可以在運(yùn)行時(shí)靈活地添加、刪除或重排數(shù)據(jù)項(xiàng)。
動(dòng)態(tài)內(nèi)存管理可以在運(yùn)行時(shí)分配更多的內(nèi)存空間或釋放掉不再需要的空間,因而可以優(yōu)化存儲(chǔ)空間的使用。
所以———由于無(wú)法預(yù)知在運(yùn)行時(shí)數(shù)組元素的使用情況,在程序中預(yù)定義的數(shù)組大小,如果過小,會(huì)導(dǎo)致程序運(yùn)行失敗;如果過大,則會(huì)浪費(fèi)內(nèi)存空間。
如果在運(yùn)行時(shí)根據(jù)實(shí)際需要來決定內(nèi)存的使用情況,則可以很好的解決以上問題。
總結(jié)
到此這篇關(guān)于C語(yǔ)言中動(dòng)態(tài)內(nèi)存的文章就介紹到這了,更多相關(guān)C語(yǔ)言動(dòng)態(tài)內(nèi)存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C語(yǔ)言編程動(dòng)態(tài)內(nèi)存開辟實(shí)現(xiàn)升級(jí)版通訊錄教程示例
- C語(yǔ)言?動(dòng)態(tài)內(nèi)存管理全面解析
- C語(yǔ)言的動(dòng)態(tài)內(nèi)存管理的深入了解
- 詳解C語(yǔ)言動(dòng)態(tài)內(nèi)存的分配
- C語(yǔ)言動(dòng)態(tài)內(nèi)存管理介紹
- C語(yǔ)言動(dòng)態(tài)內(nèi)存管理分析總結(jié)
- 詳解C語(yǔ)言之動(dòng)態(tài)內(nèi)存管理
- C語(yǔ)言編程動(dòng)態(tài)內(nèi)存分配常見錯(cuò)誤全面分析
- C語(yǔ)言 動(dòng)態(tài)內(nèi)存開辟常見問題解決與分析流程
相關(guān)文章
C/C++ Qt 自定義Dialog對(duì)話框組件應(yīng)用案例詳解
有時(shí)候我們需要一次性修改多個(gè)數(shù)據(jù),使用默認(rèn)的模態(tài)對(duì)話框似乎不太夠用,此時(shí)我們需要自己創(chuàng)建一個(gè)自定義對(duì)話框。這篇文章主要介紹了Qt自定義Dialog對(duì)話框組件的應(yīng)用,感興趣的同學(xué)可以學(xué)習(xí)一下2021-11-11Qt中const?QString轉(zhuǎn)換?char?*可能的坑
本文主要介紹了Qt中const?QString轉(zhuǎn)換?char?*可能的坑,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07UE4 Unlua 調(diào)用異步藍(lán)圖節(jié)點(diǎn)AIMoveTo函數(shù)示例詳解
這篇文章主要為大家介紹了UE4 Unlua 調(diào)用AIMoveTo函數(shù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09五個(gè)經(jīng)典鏈表OJ題帶你進(jìn)階C++鏈表篇
做題之前呢,小編想提醒下大家,要三思而后行,不要一上來就嘎嘎敲代碼,要先學(xué)會(huì)自己畫圖分析,把自己的思路捋清楚,不要到時(shí)候?qū)懘a五分鐘,調(diào)試兩小時(shí),記住,編程思路很重要2022-03-03C++標(biāo)準(zhǔn)模板庫(kù)map的常用操作
今天小編就為大家分享一篇關(guān)于C++標(biāo)準(zhǔn)模板庫(kù)map的常用操作,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12C++調(diào)用libcurl開源庫(kù)實(shí)現(xiàn)郵件的發(fā)送功能流程詳解
libcurl是一個(gè)免費(fèi)開源的網(wǎng)絡(luò)傳輸庫(kù),支持ftp、ftps、tftp,http、https、telnet、ldap、pop3、smtp等多種協(xié)議,接下來讓我們一起來了解吧2021-11-11C++修煉之構(gòu)造函數(shù)與析構(gòu)函數(shù)
本章節(jié)我們將學(xué)習(xí)類的6個(gè)默認(rèn)成員函數(shù)中的構(gòu)造函數(shù)與析構(gòu)函數(shù),并對(duì)比C語(yǔ)言階段的內(nèi)容來學(xué)習(xí)它們的各自的特性,感興趣的同學(xué)可以參考閱讀2023-03-03