您好,登錄后才能下訂單哦!
今天小編給大家分享一下C語言的動態內存如何分配的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
首先我們要搞清楚什么是動態內存的分配
平常我們定義的數組,都是在棧區分配的空間,都是分配的空間都是固定的大小
這種分配固定大小的內存分配方法稱之為靜態內存分配
與靜態內存相對的,就是可以控制內存的分配的動態內存分配
注意:這里動態內存分配的空間是在堆區申請的,不是在棧區申請的
這里要講一下什么是棧區,什么是堆區
內存的空間并不是都是一樣的,在學習C語言時,提到的區域大致上分為棧區,堆區,和靜態區。就比如說在一個車間一樣,不同的區域做著不同的事,就有不同的功能,但是這些不同的功能又不是毫不相關的,他們彼此聯系,相互構成整個內存空間.
在很多時候,我們申請的空間是未知的
就比如說通訊錄,在剛剛開始用的時候很小的空間就足夠了,但是在未來你不知道你需要存下多少個號碼,這時候就存在一個問題,你定的空間需要多少個字節,當申請的太少,就會出現存不下去的情況,如果存的空間過大,有會造成一定的浪費。
在動態內存分配就可以避免這個問題,你可以運用 reallac 控制大小,當內存達到申請的空間時,就會主動擴容,也就是再次向內存申請空間。
靜態內存分配利用的空間,整個程序結束才會釋放給系統
而動態內存分配的空間,只能在函數運行結束后由系統自動釋放,需要用戶主動去釋放,可以通過利用完(就比如說打印元素,打印完),用戶再通過 free函數釋放 這塊申請的空間,當再次用動態內存申請空間時,就可以再次利用這塊空間,這樣也能在一定程度上,可以節省一定的空間。
假設棧區定義了變量
而每個變量分配內存時,之間又有一定的間隙
當定義的變量足夠多時,空隙也會很多
這時候向系統申請一個比較大且連續的空間時,雖然有足夠的空間,但是缺少了連續的空間
就無法申請到這部分空間
所以動態內存在堆區申請,就完全不必擔心棧區的空間不夠的問題
說到這里,你是不是有一個疑惑,為什么空間的內存存在棧區和堆區之分
如果感興趣,可以參考這個回答——為什么存在棧區堆區
在動態內存的分配中,離不開malloc與calloc,這兩個函數都是向內存申請空間
calloc |
頭文件 #include <stdlib.h> |
格式 void *calloc(size_t num, size_t size); |
功能 為num個大小為size字節的對象分配存儲空間,該空間內的所有位都會初始化為。 |
返回值 若分配成功,則返回一個指向已分配的空間開頭的指針;若分配失敗,則返回空指針 |
這兩個函數都是向系統申請動態內存空間,他們的頭文件,返回值和功能大致都是相同的
不同的是calloc函數開辟的空間,就會將空間的內容全部初始話為零
而,malloc函數向系統申請的空間,空間的值都是隨機的
realloc |
頭文件 #include <stdlib.h> |
格式 void *realloc(void *mem_address, unsigned int newsize); |
功能 先判斷當前的指針是否有足夠的連續空間,如果有,擴大mem_address指向的地址,并且將 mem_address返回,如果空間不夠,先按照newsize指定的大小分配空間,將原有數據從頭到尾拷貝 到新分配的內存區域,而后釋放原來mem_address所指內存區域(注意:原來指針是自動釋放,不 需要使用free),同時返回新分配的內存區域的首地址。即重新分配存儲器塊的地址。 |
返回值 如果重新分配成功則返回指向被分配內存的指針,否則返回空指針NULL。 |
講完動態內存申請的相關函數,那具體的代碼實現是什么呢
<1> double *x;
<2> x=calloc(1,sizeof(double))或者x=malloc(sizeof(double));
<3> free;
下面動態分配的內存賦值并顯示
#include<stdio.h> #include<stdlib.h> int main()//動態內存的賦值與顯示 { int* a; a = malloc(sizeof(int)); //分配動態內存 if (a == NULL) //是否成功分配了儲存空間,否則返回分配失敗 printf("分配失敗"); else { *a = 20; printf("*a=%d\n", *a); free(a); //釋放 } return 0; }
#include<stdio.h> #include<stdlib.h> int main()//動態內存的賦值與顯示 { int n = 0; int* a; int i = 0; printf("輸入分配空間元素的個數:>"); scanf_s("%d", &n); a =(int *) calloc(n,sizeof(int)); if (a == NULL) printf("分配失敗"); else { for (i = 0; i < n; i++) { *(a + i) = i; printf("*a=%d\n", *(a+i)); } free(a); } return 0; }
這里其實沒有“為數組開辟的空間”這一說
因為動態申請的空間都是一個一個的“塊”
不難發現,calloc與malloc的差別并不大,只有第一個參數不同
在這兩行代碼中,存在著一個小細節
a = malloc(sizeof(int));
a =(int *) calloc(n,sizeof(int));
這兩者的差別不僅僅是函數的不同,其中后者有強制類型轉換,而前者沒有
實際上在C語言的標準上,有無強制類型轉換都是行得通的(當然在c++必須將強制類型轉換)
因為無論是calloc還是malloc,他們的返回值都是void* ,這里的void*實際上可以轉換為int*類型或者其他類型,換句話說,就是返回的指針是兼容所有類型的萬能指針。
即指向void型的指針可以指向任意類型的對象,是一種特殊類型的指針。
指向void型的指針的值可以賦給指向任意類型的指針,反之亦可。
#include<stdlib.h> #include<stdio.h> int main() { int* a; int i = 0; a=(int *)calloc(10,sizeof(int)); if (a == NULL) printf("分配失敗"); //使用 else { for (i = 0; i < 10; i++) { *(a + i) = i; printf("*a=%d\n", *(a + i)); } //需要擴容 int* ret = realloc(a, 80); if (ret != NULL) { a = ret; } free(a); a=NULL; } }
擴容不能直接就a=realloc(a, 80),需要中間引一個中間變量*ret
情況一(在a的地址處,有空余的空間來擴容)
情況二 (在a的地址處,沒有空余的空間來擴容,但是有其他的空間可存儲擴容后的空間)
情況三(reallo調整空間失敗)
在這三種情況中,第一種的地址不變
第二種會在一個新的地方申請足夠大的地方,此時的地址不在是a原先的地址
第三種就擴容失敗,就會導致擴容前申請的空間,也發生了改變,所以不能直接用a來重新賦值。
以上就是“C語言的動態內存如何分配”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。