網站首頁 編程語言 正文
前言
關于動態內存管理,可能有學習過的小伙伴,也有沒有聽說過的。沒有聽說過的小伙伴會覺得很奇怪啊,為什么要動態開辟內存,內存怎么還能是動態的。給不知道的小伙伴解釋一下。咱們平時在內存開辟空間也就是在棧區(局部變量,函數參數等等),靜態區(全局變量,static修飾的局部變量等等)開辟空間。只能是用多少開辟多少,是非常局限的。有時候我們需要的空間大小在程序運行的時候才能知道,那數組的編譯時開辟空間的方式就不能滿足了,所以就試試動態內存存儲。而動態內存開辟的空間都是在內存中的堆空間的。
1.關于動態內存的函數
1.1 malloc和free函數
malloc這個函數向內存申請一塊連續可用的空間,并返回指向這塊空間的指針,如果開辟成功,則返回一個指向開辟好空間的指針;如果開辟失敗,則返回一個NULL指針,因此malloc的返回值一定要做檢查。
free函數專門是用來做動態內存的釋放和回收的。如果參數 ptr 指向的空間不是動態開辟的,那free函數的行為是未定義的;如果參數 ptr 是NULL指針,則函數什么事都不做。
?
說明:
該函數設計的巧妙的一點就是返回值為void*,因為函數創造者并不知道使用者是想以什么樣的類型指針來接收動態開辟的空間,所以使用者在使用時只需要強行轉換成自己想要的類型就可以:
int* p = (int*)malloc(40);//假設是整型時的例子
在使用完動態開辟的空間后記得要用free函數向操作系統釋放開辟的空間,并且將指針賦為空指針:
int* p = (int*)malloc(40); //...... free(p);//避免內存泄漏 p = NULL;//原指針指向的位置既然已經還給操作系統的,就將指針賦為空指針,避免野指針等問題
?如果參數 size 為0,malloc的行為是標準是未定義的,取決于編譯器。
需要引頭文件stdlib.h
1.2 calloc函數
?calloc可與malloc函數相對照來學習,calloc函數的功能是為 num 個大小為 size 的元素開辟一塊空間,并且把空間的每個字節初始化為0。與malloc有兩點不同:
參數不同,calloc需要指明開辟空間的數據類型和該類型數據的個數,而malloc是全部字節數;
calloc在開辟空間的同時將空間內的全部字節初始化為0.
1.3 realloc函數
?realloc函數用來調整開辟空間的大小,有時可能開辟的空間小了,有時候可能開辟的大了,都可以通過realloc函數來修改,并且會將原來內存中的數據移動到新的空間。
realloc在調整空間大小時有兩種情況:
原有空間后有足夠大的空間,這種情況下擴展內存就直接原有內存之后直接追加空間,原來空間的數據不發生變化,返回值為原來位置的指針;
?2.原有空間后沒有足夠大的空間,這時便在堆空間找到大小合適的連續空間使用,并將原有空間的數據轉移到新的空間返回值為新空間的地址。
int main() { int *str = (int*)malloc(10); if(str != NULL) { //..... } else { exit(EXIT_FAILURE); } //擴展容量 //代碼1 str = (int*)realloc(str, 1000);//這樣可以嗎?(如果申請失敗會返回一個空指針!!!) //修改代碼2 int*p = NULL; p = realloc(str, 1000); if(p != NULL) { str = p; } //... free(str); return 0; }
2.常見的動態內存錯誤
2.1 對NULL指針解引用
int* p = (int*)malloc(40); *p=10; free(p);
這就是忽略了返回值可能是空指針的可能,如果開辟失敗會返回空指針。所以最好的做法就是判斷一下指針是否為空,然后再進行下一步。
int* p = (int*)malloc(40); if(p != NULL) { *p=10; } free(p);
2.2 對動態內存開辟的空間越界訪問
就類似于使用數組時對數組越界訪問。
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;//當i是10的時候越界訪問 } free(p);
2.3?對非動態開辟內存使用free釋放
int a = 0; int* p = &a; free(p);
通過查閱MSDN可以發現: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函數動態開辟的空間可能會導致后續的分配請求并且導致錯誤。
2.4?使用free釋放一塊動態開辟內存的一部分
int *p = (int *)malloc(100); p++; free(p);//p不再指向動態內存的起始位置
會導致動態開辟的空間無法完全釋放,進而可能會導致內存泄漏。
2.5 對同一塊動態內存多次釋放
int *p = (int *)malloc(10); free(p); free(p);//重復釋放
2.6 內存泄漏
void test() { int *p = (int *)malloc(100); if(NULL != p) { *p = 20; } } int main() { test(); return 0; }
如果使用完動態內存又不釋放則會導致這塊內存無法在后續被利用,導致內存泄漏。動態開辟的空間一定要釋放,并且正確釋放。
補充:為什么要引入動態內存分配
1.指針只能指向一個確切的內存空間,欲使用一個數據,必須先設定一個變量來保存它么?
2.在程序設計時,數據多為動態的。即程序運行時數據項的數量是變化的。
3.用數組保存多個元素時,很難預知實際運行時存儲的元素個數,往往會導致預定義的元素個數不足或過多
例如:電話簿的管理程序。當添加新聯系人時,數據項將增加;刪除聯系人時,數據項將減少。
動態數據結構可以在運行時靈活地添加、刪除或重排數據項。
動態內存管理可以在運行時分配更多的內存空間或釋放掉不再需要的空間,因而可以優化存儲空間的使用。
所以———由于無法預知在運行時數組元素的使用情況,在程序中預定義的數組大小,如果過小,會導致程序運行失敗;如果過大,則會浪費內存空間。
如果在運行時根據實際需要來決定內存的使用情況,則可以很好的解決以上問題。
總結
原文鏈接:https://blog.csdn.net/weixin_60720508/article/details/123282869
相關推薦
- 2023-02-25 Golang嵌入資源文件實現步驟詳解_Golang
- 2022-04-15 ASP.NET?Core托管模型CreateDefaultBuilder()方法_基礎應用
- 2022-12-05 關于Word2Vec可視化展示_python
- 2022-07-02 python?np.arange?步長0.1的問題需要特別注意_python
- 2022-04-23 使用matplotlib庫實現圖形局部數據放大顯示的實踐_python
- 2022-10-12 排查服務器異常流量教程詳解_nginx
- 2023-12-22 onReachBottom觸底觸發事件
- 2022-08-27 asp.net中MVC的處理流程詳解_基礎應用
- 最近更新
-
- 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同步修改后的遠程分支