歡迎拜訪:霧里看山-CSDN博客
本篇主題:C語言動態內存管理(下)
發布時間:2025.3.18
隸屬專欄:C語言
目錄
- 動態內存常見錯誤
- 內存泄漏(Memory Leak)
- 典型場景
- 后果
- 解決方案
- 懸掛指針(Dangling Pointer)
- 錯誤示例
- 深層原理
- 修復方案
- 雙重釋放(Double Free)
- 危險操作
- 系統表現
- 防護措施:
- 越界訪問(Out-of-Bounds)
- 典型錯誤
- 內存影響
- 未初始化訪問
- 問題代碼
- 隨機性危害
- 防御性編程
- 釋放棧區內容
- 錯誤示例
- 解決方案
- 未全部釋放
- 錯誤示例
- 解決方案
- C/C++程序的內存開辟
動態內存常見錯誤
內存泄漏(Memory Leak)
典型場景
void process_data() {int* buffer = malloc(1024 * sizeof(int));// 忘記調用 free(buffer)
}
后果
- 程序持續運行時會不斷消耗內存
- 長期運行的服務可能因此崩潰
解決方案
- 遵循申請與釋放成對出現原則
- 使用RAII模式(C可用
__attribute__((cleanup))
擴展)
懸掛指針(Dangling Pointer)
錯誤示例
int* create_int() {int value = 42;return &value; // 返回局部變量地址
}int main() {int* ptr = create_int();printf("%d", *ptr); // 不可預測結果
}
深層原理
- 棧幀銷毀后,原地址可能被其他數據覆蓋
- 堆內存釋放后若未置空,指針仍保存失效地址
修復方案
及時釋放,釋放后立即置空
free(ptr);
ptr = NULL; // 立即置空
雙重釋放(Double Free)
危險操作
對同一地址空間進行多次釋放
char* str = malloc(64);
free(str);
free(str);
系統表現
- 可能立即引發
segmentation fault
- 可能破壞堆管理結構導致后續
malloc
失敗
防護措施:
- 使用釋放后置空的編程規范
- 在復雜邏輯中明確資源所有權
越界訪問(Out-of-Bounds)
典型錯誤
數組只開辟了[0,4]
的空間,訪問時卻訪問了下標為5的空間。
int* arr = malloc(5 * sizeof(int));
for(int i=0; i<=5; i++) { // 索引0-4有效arr[i] = i; // i=5時越界
}
內存影響
- 可能覆蓋相鄰內存的控制信息
- 可能修改其他變量值導致邏輯錯誤
未初始化訪問
問題代碼
內存開辟出來未進行初始化就直接訪問。
int* p = malloc(sizeof(int));
printf("%d", *p);
隨機性危害
- 可能意外修改關鍵內存區域
- 在不同運行環境中表現不一致
防御性編程
指針定義時顯示初始化, 指針使用時進判空。
int* p = malloc(sizeof(int));
*p = 10;
printf("%d", *p);
釋放棧區內容
錯誤示例
對于非動態開辟出來的內存進行釋放
void test()
{int a = 10;int *p = &a;free(p);
}
解決方案
- 遵循申請與釋放成對出現原則
- 使用RAII模式(C可用
__attribute__((cleanup))
擴展)
未全部釋放
錯誤示例
在釋放內存的時候,創建時的指針和原來的指針已經不在同一個位置,直接釋放則會有內存錯誤。
void test()
{int *p = (int *)malloc(100);p++;free(p);
}
解決方案
在創建的時候,使用一個指針記錄起始位置,
void test()
{int *p = (int *)malloc(100);int *ptr=p;p++;free(ptr);
}
C/C++程序的內存開辟
C/C++程序內存分配的幾個區域:
- 棧區(stack):在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束時這些存儲單元自動被釋放。棧內存分配運算內置于處理器的指令集中,效率很高,但是分配的內存容量有限。 棧區主要存放運行函數而分配的局部變量、函數參數、返回數據、返回地址等。
- 堆區(heap):一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。分配方式類似于鏈表。
- 數據段(靜態區)(static)存放全局變量、靜態數據。程序結束后由系統釋放。
- 代碼段:存放函數體(類成員函數和全局函數)的二進制代碼。
實際上普通的局部變量是在棧區分配空間的,棧區的特點是在上面創建的變量出了作用域就銷毀。
但是被static
修飾的變量存放在數據段(靜態區),數據段的特點是在上面創建的變量,直到程序結束才銷毀所以生命周期變長。
?? 寫在最后:以上內容是我在學習以后得一些總結和概括,如有錯誤或者需要補充的地方歡迎各位大佬評論或者私信我交流!!!