C語(yǔ)言動(dòng)態(tài)內(nèi)存規(guī)劃詳解
動(dòng)態(tài)內(nèi)存規(guī)劃
用C語(yǔ)言寫程序時(shí),因?yàn)檎Z(yǔ)言的一些特性使用數(shù)組的時(shí)候只能用常量來(lái)申明數(shù)組,就導(dǎo)致數(shù)組的內(nèi)存被卡得很死,不能根據(jù)我們的實(shí)際需求靈活的使用內(nèi)存空間。有些空間的大小在程序運(yùn)行時(shí)才能知道,那數(shù)組的編譯時(shí)開(kāi)辟空間的方式就不能滿足了,這時(shí)候就只有動(dòng)態(tài)開(kāi)辟內(nèi)存
動(dòng)態(tài)內(nèi)存函數(shù)的介紹
malloc函數(shù)
void* malloc(size_t size);
這個(gè)函數(shù)的 作用是向內(nèi)存申請(qǐng)一快連續(xù)可用的空間,并返回指向這塊空間的指針。
- 如果開(kāi)辟成功,則返回一個(gè)指向開(kāi)辟好空間的指針 。
- 如果開(kāi)辟失敗,則返回一個(gè)NULL指針,因此malloc的返回值一定要做檢查
- 返回值的 類型是void*,所以malloc函數(shù)并不知道開(kāi)辟空間的類型,具體在使用的 時(shí)候使用者自己來(lái)決定。
- 如果參數(shù)size為0,malloc的行為是標(biāo)準(zhǔn)未定義的,取決于編譯器
free函數(shù)
當(dāng)我們向內(nèi)存空間申請(qǐng)的空間 使用完之后一定要用free()函數(shù)將申請(qǐng)的內(nèi)存空間釋放掉,否則可能會(huì)導(dǎo)致內(nèi)存泄漏
void free(void* ptr)
- 如果參數(shù)ptr指向的空間不是 動(dòng)態(tài)開(kāi)辟的,那free函數(shù)的行為是未定義的。
- 如果參數(shù)ptr是NULL指針,則函數(shù)什么事都不用做。
// malloc函數(shù) 和 free函數(shù)的使用語(yǔ)法 #include<stdio.h> #include<stdlib.h> int main(){ int* arr = (int*)malloc(sizeof(int)*10); // 因?yàn)閙alloc函數(shù)的返回值是void*所以要進(jìn)行強(qiáng)制類型轉(zhuǎn)換 if(arr == NULL){ // 判斷內(nèi)存是否開(kāi)辟成功 printf("內(nèi)存開(kāi)辟失敗\n"); return; } int i = 0; for(i = 0; i < 10; i++){ // 將數(shù)據(jù)放進(jìn)我們開(kāi)辟的空間中 arr[i] = i; } for(i = 0; i < 10; i++){ printf("%d",arr[i]); // 驗(yàn)證數(shù)據(jù)是否放進(jìn)去了 } free(arr);// 使用完空間后將它釋放 arr = NULL; return 0; }
calloc函數(shù)
C語(yǔ)言還提供了一個(gè)函數(shù)叫做calloc,calloc函數(shù)也用來(lái)動(dòng)態(tài)內(nèi)存分配
void* calloc(size_t num, size_t size);
- 函數(shù)的功能是為 num個(gè)大小為size的元素開(kāi)辟一塊空間,并且把空間的每個(gè)字節(jié)初始化為0
- 與函數(shù)malloc的區(qū)別只在于calloc會(huì)在返回地址之前把申請(qǐng)的空間的每個(gè)字節(jié)初始化為全0
#include<stdio.h> #include<stdlib.h> int main(){ int* arr = (int*)calloc(10, sizeof(int)); if(NULL != arr){ int i = 0; for(i = 0; i < sizeof(int)*10; i++){ printf("%d ",*((char*)arr+i)); } } free(arr); arr = NULL; return 0; }
realloc函數(shù)
realloc函數(shù)的出現(xiàn)讓動(dòng)態(tài)內(nèi)存管理更加靈活,有時(shí)我們會(huì)發(fā)現(xiàn)之前申請(qǐng)的空間太小了不夠用,有時(shí)也會(huì)覺(jué)得申請(qǐng)的空間太大用不了那么多。為了能夠更加靈活的管理內(nèi)存我們可以使用realloc函數(shù)對(duì)開(kāi)辟的內(nèi)存空間進(jìn)行調(diào)整
void* realloc(void* ptr, size_t size);
- ptr是要調(diào)整的內(nèi)存地址
- size是調(diào)整之后新的內(nèi)存大小
- 這個(gè)函數(shù)調(diào)整原內(nèi)存空間大小的基礎(chǔ)上,還會(huì)將原來(lái)內(nèi)存中的數(shù)據(jù) 移動(dòng)到新的空間
- realloc在調(diào)整內(nèi)存空間的內(nèi)存時(shí)有兩種情況,**第一種情況:**原有空間之后足夠大的空間,這時(shí)會(huì)在原有空間之后的連續(xù)空間開(kāi)辟新的空間。**第二種情況:**原有的空間之后沒(méi)有足夠大空間,這種情況是在堆空間上另找一個(gè)合適大小的連續(xù)空間來(lái)使用,這樣函數(shù)返回的是一個(gè)新的內(nèi)存地址。所以在用realloc函數(shù)調(diào)整空間的時(shí)候需要用一個(gè)臨時(shí)指針變量來(lái)存放realloc的返回值,再把變量有賦值給之前的指針變量
#include<stdio.h> #include<stdlib.h> int main(){ int* arr = (int*)malloc(sizeof(10)); if(NULL != arr){ // 業(yè)務(wù)處理 } // 當(dāng)開(kāi)辟的空間用完時(shí) int* tmp = (int*)realloc(arr, sizeof(int)*20); if(NULL != tmp){ arr = tmp; } return 0; }
柔性數(shù)組
typedef struct arr_type{ int i; int a[]; // 柔性數(shù)組成員 }type_arr;
- 結(jié)構(gòu)體中的柔性數(shù)組成員前面必須至少有一個(gè)其他成員。
- sizeof返回的 這種結(jié)構(gòu)大小不包括柔性數(shù)組的內(nèi)存。
- 包含柔性數(shù)組成員的結(jié)構(gòu)用malloc函數(shù)進(jìn)行 內(nèi)存的動(dòng)態(tài)分配,并且分配的內(nèi)存應(yīng)該大于結(jié)構(gòu)的大小,以適應(yīng)柔性數(shù)組的預(yù)期大小
typedef struct arr{ int i; int a[]; }arr; printf("%d\n",sizeof(arr));// 輸出的是4
柔性數(shù)組的使用
int main() { struct rou_arr* ps = (struct rou_arr*)malloc(sizeof(int) + 10 * sizeof(int)); if (ps == NULL) { printf("%s", strerror(errno)); } ps->i = 10; int i = 0; for (i = 0; i < 10; i++) { ps->arr[i] = i; } for (i = 0; i < 10; i++) { printf("%d ", ps->arr[i]); } // 對(duì)柔性數(shù)組進(jìn)行擴(kuò)容 struct rou_arr* ptr = (struct rou_arr*)realloc(ps, sizeof(int) + sizeof(int) * 20); if (ptr == NULL) { printf("realloc is failure\n"); return -1; } ps = ptr; for (i = 0; i < 20; i++) { ps->arr[i] = i; } for (i = 0; i < 20; i++) { printf("%d ", ps->arr[i]); } return 0; }
柔性數(shù)組的好處有兩個(gè),一是方便內(nèi)存釋放,二是有利于訪問(wèn)速度
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之二叉樹(shù)的非遞歸后序遍歷算法
這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之二叉樹(shù)的非遞歸后序遍歷算法的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下2017-10-10C++實(shí)現(xiàn)簡(jiǎn)單的學(xué)生成績(jī)管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡(jiǎn)單的學(xué)生成績(jī)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03詳解C語(yǔ)言動(dòng)態(tài)內(nèi)存的分配
這篇文章主要為大家介紹了C語(yǔ)言動(dòng)態(tài)內(nèi)存的分配,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2021-12-12解讀堆排序算法及用C++實(shí)現(xiàn)基于最大堆的堆排序示例
把待排序的數(shù)組構(gòu)造出最大堆是進(jìn)行堆排序操作的基本方法,這里將帶大家來(lái)解讀堆排序算法及用C++實(shí)現(xiàn)基于最大堆的堆排序示例,首先從堆排序的概念開(kāi)始:2016-06-06C語(yǔ)言中關(guān)于sizeof 和 strlen的區(qū)別分析
本文通過(guò)示例簡(jiǎn)單分析了4種情況下C語(yǔ)言中sizeof 和 strlen的區(qū)別,算是個(gè)人經(jīng)驗(yàn)的一個(gè)小小的總結(jié),如有遺漏還請(qǐng)大家告知。2015-02-02C語(yǔ)言中#define在多行宏定義出錯(cuò)的原因及分析
這篇文章主要介紹了C語(yǔ)言中#define在多行宏定義出錯(cuò)的原因及分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02Linux網(wǎng)絡(luò)編程之UDP Socket程序示例
這篇文章主要介紹了Linux網(wǎng)絡(luò)編程之UDP Socket程序示例,有助于讀者在實(shí)踐中掌握UDP協(xié)議的原理及應(yīng)用方法,需要的朋友可以參考下2014-08-08