網站首頁 編程語言 正文
一、malloc
這個函數向堆區申請一塊連續的空間,并返回這塊內存的地址。
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
free(p);
p = NULL;
return 0;
}
如果開辟失敗,則返回一個NULL指針,因此malloc的返回值一定要做檢查。
如果參數 size為0,malloc的行為是標準是未定義的,取決于編譯器。
二、free
free函數用來釋放動態開辟的內存。free的指針必須是指向動態內存空間的起始地址。
如果參數 ptr 指向的空間不是動態開辟的,那free函數的行為是未定義的。
如果參數 ptr 是NULL指針,則函數什么事都不做。
三、calloc
num:要動態開辟的元素個數
size:每個元素的大小
calloc=malloc+memset
calloc和malloc的區別就在于calloc會將動態內存開辟的空間全部初始化為0
四、realloc
ptr:需要擴容的原始地址
size:擴容后的總大小
1、realloc在擴容時的情況
1、擴容時后方空間足夠,將在后方繼續擴容,返回原始地址
2、擴容時后方空間已被使用,將在新的一塊區域進行擴容,并將原始數據拷貝至新的區域,free原始地址指向的內存,并返回內存塊的地址。
3、空間不足,無法擴容,返回空指針
2、realloc也能實現malloc功能
int main()
{
int* p = (int*)realloc(NULL, 40);
return 0;
}
realloc在當malloc使用時,第一個參數傳空指針即可。
五、使用動態內存的常見錯誤
1、free空指針
void text()
{
int* p = (int*)realloc(NULL, 40);
if (p == NULL)//判斷p是否為空指針
{
return;
}
*p = 20;
}
如果開辟空間后,沒有判斷指針p是否是空指針,如果動態內存開辟失敗,那么*p將會解引用空指針。
2、對動態開辟的空間越界訪問
void text()
{
int* p = (int*)realloc(NULL, 40);
int* m = p;
if (p == NULL)
{
return;
}
for (int i = 0; i <= 10; i++)
{
p[i] = i;//越界
p++;
}
}
3、對非動態開辟內容free
void text()
{
int arr[] = {1,2,3};
int* p = arr;
free(p);//不能對非動態開辟的空間進行free
}
4、只free動態開辟空間的一部分
void text()
{
int* p = (int*)malloc(40);
p++;
free(p);//p不再指向動態開辟空間的起始位置
}
實際寫代碼的時候還是得多注意這種情況,指針p在使用的過程中已經不再是初始位置,free(p)會崩潰。
5、對同一塊內存多次free
void text()
{
int* p = (int*)realloc(NULL, 40);
free(p);
//p = NULL;
free(p);
}
free(p)后及時將p置為空指針,哪怕p被多次free也沒問題。
6、動態內存空間忘記釋放(內存泄漏)
void text()
{
int* p = (int*)realloc(NULL, 40);
int a = 0;
scanf("%d", &a);
if (a == 5)
return;
free(p);
p = NULL;
}
當函數提前終止,沒有機會走到free,可能會造成內存泄漏
另一種可能是調用了動態開辟內存的函數,使用者未在外部進行free
六、柔性數組
1、柔性數組的概念
C99中,結構體中最后一個成員變量可以是未知大小的數組
struct S
{
int a;
int arr[0];//這里的arr[0]代表未知大小的數組
};
//或者如下寫法:
struct S
{
int a;
int arr[];
};
2、柔性數組的特點
結構體中的柔性數組成員前面必須至少一個其他成員。
sizeof 返回的這種結構大小不包括柔性數組的內存。
包含柔性數組成員的結構用malloc ()函數進行內存的動態分配,并且分配的內存應該大于結構的大小,以適應柔性數組的預期大小。
3、柔性數組的使用場景
場景:將結構體中所有的成員變量全部在堆區開辟
使用柔性數組:
struct S
{
int a;
int arr[0];
};
int main()
{
struct S s;
struct S* ps = &s;
ps = (struct S*)realloc(NULL,sizeof(s) + 40);//首次開辟空間,傳NULL
if (ps == NULL)
{
exit(-1);
}
free(ps);
ps = NULL;
return 0;
}
注意此處的realloc第一個參數傳入的是NULL而不是&s,傳入&s會崩潰,是因為這是第一次動態內存開辟,此處傳入NULL相當于使用malloc
完成開辟后s在內存中的存儲如下圖:
使用常規結構體:
struct S
{
int a;
int* parr;
};
int main()
{
struct S* p = (struct S*)malloc(sizeof(struct S));//對結構體動態開辟空間
if (p == NULL)
{
exit(-1);
}
int* tmp= (int*)malloc(sizeof(int) * 2);//在堆區動態開辟一塊空間
if (tmp == NULL)
{
exit(-1);
}
p->parr = tmp;
free(p->parr);//釋放時,需要先釋放p->parr指向的空間
p->parr = NULL;
free(p);//再將結構體指針p指向的空間釋放
p = NULL;
return 0;
}
完成開辟后s在內存中的存儲如下圖:
4、柔性數組的優點
1、在上述條件下,使用柔性數組方便動態內存釋放。如果我們的代碼是在一個給別人用的函數中,你在里面做了二次內存分配,并把整個結構體返回給用戶。用戶調用free可以釋放結構體,但是用戶并不知道這個結構體內的成員也需要free,可能會造成內存泄漏。所以,如果我們把結構體的內存以及其成員要的內存一次性分配好了,并返回給用戶一個結構體指針,用戶做一次free就可以把所有的內存給釋放掉。
2、連續的內存有益于提高訪問速度,也有益于減少內存碎片。
原文鏈接:https://blog.csdn.net/gfdxx/article/details/125840384
相關推薦
- 2022-12-10 Android入門之日歷選擇與時間選擇組件的使用_Android
- 2022-05-25 ASP.NET?MVC+EF實現異步增刪改查_實用技巧
- 2022-09-15 C語言實現學生成績管理系統課程設計_C 語言
- 2023-07-06 css flex實現div固定在瀏覽器右下角
- 2022-06-24 Python+matplotlib實現簡單曲線的繪制_python
- 2022-08-02 Python+Selenium實現瀏覽器標簽頁的切換_python
- 2022-02-21 MyBatis There is no getter for property named ‘xxx
- 2022-04-17 python使用openpyxl讀取日期并修改excel
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支