、
文章目錄
- 一、為什么需要動態內存分配?
- 二、malloc 和 free
- 1. malloc
- 2. free
- 三、calloc 和 realloc
- 1. calloc
- 2. realloc
- 四、常見的動態內存錯誤
- 1. 對 NULL 解引用
- 2. 越界訪問
- 3. 對非動態內存使用 free
- 4. 釋放部分動態內存
- 5. 多次釋放同一塊內存
- 6. 內存泄漏
- 五、動態內存經典題目分析
- 六、柔性數組(Flexible Array)
- 1.定義
- 2.特點
- 3.優勢
- 七、C/C++ 程序內存區域劃分
- 總結
一、為什么需要動態內存分配?
已掌握的內存開辟方式:
· int val = 20; → 棧上開辟4字節
· char arr[10] = {0}; → 棧上開辟10字節連續空間
局限性:
· 空間大小固定
· 數組長度必須在編譯時確定
動態內存分配的優勢:
· 程序運行時才能確定所需空間大小
· 動態申請和釋放,更靈活
二、malloc 和 free
1. malloc
void* malloc(size_t size);
· 成功:返回指向開辟空間的指針
· 失敗:返回 NULL
· 返回值類型為 void*,需強制轉換
· 若 size = 0,行為未定義(編譯器決定)
2. free
void free(void* ptr);
· 釋放動態開辟的內存
· 若 ptr 非動態開辟,行為未定義
· 若 ptr 為 NULL,函數什么也不做
示例:
#include <stdio.h>
#include <stdlib.h>int main() {int num;scanf("%d", &num);int* ptr = (int*)malloc(num * sizeof(int));if (ptr != NULL) {for (int i = 0; i < num; i++) {ptr[i] = 0;}}free(ptr);ptr = NULL; // 避免野指針return 0;
}
三、calloc 和 realloc
1. calloc
void* calloc(size_t num, size_t size);
· 為 num 個大小為 size 的元素開辟空間
· 并將每個字節初始化為 0
· 與 malloc 的區別:自動初始化
示例:
int* p = (int*)calloc(10, sizeof(int));
// 輸出:0 0 0 0 0 0 0 0 0 0
2. realloc
void* realloc(void* ptr, size_t size);
· 調整已開辟內存的大小
· ptr:原內存地址
· size:新大小
· 返回新內存起始地址
兩種情況:
- 原空間后方有足夠空間 → 直接擴展
- 原空間后方不足 → 另找空間,拷貝數據,釋放原空間
使用建議:
int* tmp = (int*)realloc(ptr, new_size);
if (tmp != NULL) {ptr = tmp;
} else {// 處理失敗
}
四、常見的動態內存錯誤
1. 對 NULL 解引用
int *p = (int*)malloc(INT_MAX/4);
*p = 20; // 可能崩潰
2. 越界訪問
for (i = 0; i <= 10; i++) {*(p + i) = i; // i=10 越界
}
3. 對非動態內存使用 free
int a = 10;
int *p = &a;
free(p); // 錯誤
4. 釋放部分動態內存
p++;
free(p); // p 不指向起始位置
5. 多次釋放同一塊內存
free(p);
free(p); // 重復釋放
6. 內存泄漏
void test() {int *p = (int*)malloc(100);// 忘記 free
}
五、動態內存經典題目分析
題目1:
void GetMemory(char *p) {p = (char*)malloc(100);
}
// 錯誤:傳值調用,str 仍為 NULL
題目2:
char* GetMemory() {char p[] = "hello world";return p; // 返回棧內存地址,危險!
}
題目3:
void GetMemory(char **p, int num) {*p = (char*)malloc(num);
}
// 正確:傳地址,可修改 str
題目4:
free(str);
if (str != NULL) { // str 已成為野指針strcpy(str, "world"); // 非法訪問
}
六、柔性數組(Flexible Array)
1.定義
struct st_type {int i;int a[]; // 或 int a[0];
};
2.特點
· 必須是結構最后一個成員
· sizeof 不包含柔性數組內存
· 需用 malloc 動態分配額外空間
使用:
type_a *p = malloc(sizeof(type_a) + 100 * sizeof(int));
p->i = 100;
for (int i = 0; i < 100; i++) {p->a[i] = i;
}
free(p);
3.優勢
· 一次分配、一次釋放
· 內存連續,訪問速度快,減少內存碎片
七、C/C++ 程序內存區域劃分
區域 內容說明
棧區(stack) 局部變量、函數參數、返回地址等,系統自動分配釋放
堆區(heap) 動態分配的內存,需手動管理
數據段(靜態區) 全局變量、靜態變量,程序結束釋放
代碼段 可執行代碼、只讀常量
內存映射段 文件映射、動態庫、匿名映射
內核空間 用戶代碼不可訪問
總結
· 動態內存管理使得程序在運行時能靈活申請和釋放內存
· 使用 malloc、calloc、realloc 申請,free 釋放
· 注意避免常見錯誤:空指針、越界、重復釋放、內存泄漏等
· 柔性數組適用于動態大小的結構體成員
· 理解內存區域劃分有助于更好地管理內存