目錄

1、為什么要有動態(tài)內(nèi)存分配
2、動態(tài)內(nèi)存函數(shù)介紹
1、malloc
2、free
3、calloc
?編輯
4、realloc
3、動態(tài)內(nèi)存常見的錯誤
4、動態(tài)內(nèi)存開辟相關(guān)好題
5、c/c++程序內(nèi)存開辟示意圖
int a,? int arr[10]? 是固定地向內(nèi)存申請連續(xù)的一塊空間,但不能變長或變短隨時調(diào)整。
在我們之前寫的靜態(tài)版通訊錄中,我們創(chuàng)建了一個peopleinfo類型的數(shù)組date[100]用來存放100個人的個人信息,但是當(dāng)我們的人員信息較小時,100個結(jié)構(gòu)體顯得有些浪費,而當(dāng)我們所需存放的信息超過100時又不夠用,隨之我們就得修改這個數(shù)字,但是學(xué)了動態(tài)內(nèi)存管理之后,我們可以動態(tài)地分配內(nèi)存空間變大或變小,從而有效利用空間。
1、為什么要有動態(tài)內(nèi)存分配int val = 20;//在棧空間上開辟四個字節(jié)
char arr[10] = {0};//在棧空間上開辟10個字節(jié)的連續(xù)空間
但是上述的開辟空間的方式有兩個特點:
1. 空間開辟大小是固定的。
2. 數(shù)組在申明的時候,必須指定數(shù)組的長度,它所需要的內(nèi)存在編譯時分配。
但是對于空間的需求,不僅僅是上述的情況。有時候我們需要的空間大小在程序運行的時候才能知道,
那數(shù)組的編譯時開辟空間的方式就不能滿足了。
這時候就只能使用動態(tài)內(nèi)存開辟了。

#include

這個函數(shù)向內(nèi)存申請一塊連續(xù)可用的空間,并返回指向這塊空間的指針。
如果開辟成功,則返回一個指向開辟好空間的指針。
如果開辟失敗,則返回一個NULL指針,因此malloc的返回值一定要做檢查。
返回值的類型是 void* ,所以malloc函數(shù)并不知道開辟空間的類型,具體在使用的時候使用者自己
來決定。
如果參數(shù) size 為0,malloc的行為是標(biāo)準(zhǔn)是未定義的,取決于編譯器。
先在堆區(qū)上動態(tài)申請一定空間,使用后應(yīng)該還給操作系統(tǒng),如果不主動還,程序結(jié)束后會自動還,但是如果程序一直不結(jié)束,就一直“占著不用”,就會造成空間的浪費。
2、free用來釋放、歸還申請的內(nèi)存

int main()
{
//申請40個字節(jié),用來存放10個整型
int* p = (int*)malloc(40);
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
//存放 1--10
int i = 0;
for (i = 0; i< 10; i++)
{
*(p + i) = i + 1;
}
for (i = 0; i< 10; i++)
{
printf("%d ", *(p+i));
}
//free釋放申請的內(nèi)存
free(p);
return 0;
}
用malloc申請后,內(nèi)存中為隨機值,使用時可給它們賦值,當(dāng)free后,又變?yōu)殡S機值。

仔細(xì)觀察,我們可以發(fā)現(xiàn),雖然這塊空間的值發(fā)生了變化,但是指針p指向的地址free前后沒有變化。因此,當(dāng)我們free還給操作系統(tǒng)后,p仍指向這塊空間。此時*p就會導(dǎo)致非法訪問,因此我們需要將p制為NULL,避免非法訪問。
free(p);
p = NULL;總結(jié):malloc申請空間后不會初始化,使用前要判斷是否成功申請(是否返回NULL),使用后要free還給操作系統(tǒng),然后將用于接收這塊內(nèi)存空間的指針p置為NULL。

申請失敗時返回NULL,并打印錯誤原因(沒有足夠空間)。
void? free(void * ptr)
free函數(shù)用來釋放動態(tài)開辟的內(nèi)存。
如果參數(shù) ptr 指向的空間不是動態(tài)開辟的,那free函數(shù)的行為是未定義的。
如果參數(shù) ptr 是NULL指針,則函數(shù)什么事都不做。


由上圖我們可以知道,malloc不會初始化,calloc會將每個元素先初始化為0,可以按需用。由于calloc需要初始化,效率比malloc稍低,此外沒有其它區(qū)別,都需要進行相關(guān)步驟。
4、realloc

int main()
{
int* p = (int*)malloc(5 * sizeof(int));
if (NULL == p)
{
perror("malloc");
return 1;
}//使用
int i = 0;
for (i = 0; i< 5; i++)
{
p[i] = 1;
}//空間不夠,增加5個整型的空間
//此時不能用p接收
int* ptr = (int*)realloc(p, 10 * sizeof(int));
//先用ptr接收,再賦給p,防止返回NULL,p找不到原來的數(shù)據(jù)
if (ptr != NULL)
{
p = ptr;
ptr = NULL;//釋放但不置空,需手動置空
}
//繼續(xù)使用
for (i = 0; i< 10; i++)
{
printf("%d ", p[i]);
}//realloc會把舊的空間釋放,不用自己釋放
free(p);
p = NULL;
}
1、對NULL解引用(未判斷是否為空)
2、非法訪問內(nèi)存,越界訪問(解引用野指針)
3、對非動態(tài)開辟內(nèi)存的空間用free釋放
void test()
{
int a = 10;
int *p = &a;
free(p);//ok?
}對棧區(qū)的空間進行釋放(x)
4、使用free釋放一塊動態(tài)開辟內(nèi)存的一部分
void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向動態(tài)內(nèi)存的起始位置
p=NULL;
}5、對同一塊內(nèi)存多次釋放
void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重復(fù)釋放
}free一個NULL空指針時,什么事都不會發(fā)生。
malloc等函數(shù)是申請一塊空間,獲得使用它的權(quán)限,free釋放后,將權(quán)限還給操作系統(tǒng),如果再訪問或是釋放,就是非法訪問。
6、動態(tài)開辟的內(nèi)存忘記釋放(內(nèi)存泄漏)
malloc和free要成對出現(xiàn),防止出現(xiàn)內(nèi)存泄漏
int* test()
//函數(shù)內(nèi)部進行了malloc操作,返回了malloc開辟的空間的起始地址
//誰接收了 要記得釋放和置空
{
int* p = (int*)malloc(100);
if (NULL == p)
{
return 1;
}
return p;
}
int main()
{
int* ptr = test();
free(ptr);
ptr = NULL;
}4、動態(tài)內(nèi)存開辟相關(guān)好題void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
int main()
{
Test();
}這里GetMemory函數(shù)是值傳遞,且沒有返回值,對str無影響。因此str還是指向NULL,即0地址處,然后調(diào)用strcpy需訪問0地址處內(nèi)容,導(dǎo)致非法訪問。
同時,上面用malloc申請了一塊空間,但是函數(shù)內(nèi)沒有釋放,函數(shù)銷毀后,p也銷毀,這塊空間就會內(nèi)存泄漏。記得malloc要與free搭配使用。
修改后,可傳入&str,用char**p接收,*P=(char*)malloc(100),使p指向開辟的100byte,進而存放拷貝的內(nèi)容,打印后free(str) str=NULL
或者將p(char*)直接返回,用str接收,因為沒有free,所以malloc(100)仍然存在,進而可以strcpy,如果此時不是malloc申請,而是利用數(shù)組,函數(shù)銷毀后,數(shù)組的空間也會釋放,如果再進行打印就不行了。(如下圖)這類問題簡稱為 返回棧空間地址的問題

可以在p前面加上static使其變?yōu)殪o態(tài)區(qū)變量,函數(shù)銷毀后它不會銷毀,或者去掉[],p變?yōu)閏har*類型,即從數(shù)組變?yōu)槌A孔址A孔址彩窃陟o態(tài)區(qū),也就是把在棧區(qū)存儲的數(shù)據(jù)放入靜態(tài)區(qū)中存儲,從而避免了返回棧空間地址的問題。
printf(str)括號內(nèi)直接加str是可以的,str是一個地址,例如printf(“hehe”),括號內(nèi)有引號+字符串,也就是首字符的地址,相當(dāng)于括號內(nèi)直接加一個地址,最終結(jié)果都是打印字符串。
void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
int main()
{
Test();
}這段代碼的整體思路沒有問題,但是會導(dǎo)致內(nèi)存泄漏,? malloc等函數(shù)需要與free共同使用
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, "hello");
free(str);
}
if(str != NULL)
{
strcpy(str, "world");
printf(str);
}free(str)后已經(jīng)沒有權(quán)限訪問了,但后面又調(diào)用strcpy訪問空間,導(dǎo)致非法訪問
開辟--釋放--置空
習(xí)題來自《高質(zhì)量C/C++編程》
5、c/c++程序內(nèi)存開辟示意圖
1. 棧區(qū)(stack):在執(zhí)行函數(shù)時,函數(shù)內(nèi)局部變量的存儲單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)
束時這些存儲單元自動被釋放。棧內(nèi)存分配運算內(nèi)置于處理器的指令集中,效率很高,但是
分配的內(nèi)存容量有限。 棧區(qū)主要存放運行函數(shù)而分配的局部變量、函數(shù)參數(shù)、返回數(shù)據(jù)、返
回地址等。
2. 堆區(qū)(heap):一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時可能由OS回收 。分
配方式類似于鏈表。
3. 數(shù)據(jù)段(靜態(tài)區(qū))(static)存放全局變量、靜態(tài)數(shù)據(jù)。程序結(jié)束后由系統(tǒng)釋放。
4. 代碼段:存放函數(shù)體(類成員函數(shù)和全局函數(shù))的二進制代碼,只讀常量(不能被修改),字符串常量。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
網(wǎng)站名稱:動態(tài)內(nèi)存分配/管理-創(chuàng)新互聯(lián)
網(wǎng)址分享:http://chinadenli.net/article42/gedec.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機網(wǎng)站建設(shè)、全網(wǎng)營銷推廣、自適應(yīng)網(wǎng)站、靜態(tài)網(wǎng)站、響應(yīng)式網(wǎng)站、品牌網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容