在 C 語言中malloc分配記憶體
- ctfm214
- 7月22日
- 讀畢需時 3 分鐘
在 C 語言中,`malloc` 用於在**堆(Heap)**上動態分配記憶體。以下是需要使用的典型場景及詳細說明:
---
### 📌 核心使用場景
#### 1️⃣ **動態資料結構**
當需要創建大小**在運行時才確定**的資料結構時:
```c
int n;
printf("請輸入陣列大小:");
scanf("%d", &n);
// 編譯時無法確定大小 → 必須用 malloc
int *arr = (int*)malloc(n * sizeof(int));
for(int i=0; i<n; i++) {
arr[i] = i*10;
}
free(arr); // 必須手動釋放!
```
#### 2️⃣ **大型記憶體需求**
當需要的記憶體超過**棧(Stack)容量**(通常約 1-8 MB):
```c
// 錯誤:可能導致棧溢出(Stack Overflow)
// int huge[1000000];
// 正確:改用堆記憶體
int *huge = (int*)malloc(1000000 * sizeof(int));
free(huge);
```
#### 3️⃣ **跨函數存活的變數**
需要讓變數在**函數返回後繼續存在**時:
```c
struct Data* create_data() {
struct Data *d = malloc(sizeof(struct Data)); // 分配在堆上
d->value = 42;
return d; // 返回指標,記憶體不會被回收
}
// 使用後必須手動釋放!
struct Data *my_data = create_data();
free(my_data);
```
#### 4️⃣ **動態字串處理**
處理長度不確定的字串時:
```c
char* read_line() {
char buffer[256]; // 臨時緩衝區
fgets(buffer, 256, stdin);
// 根據實際長度分配精確大小
char *str = malloc(strlen(buffer) + 1);
strcpy(str, buffer);
return str;
}
```
#### 5️⃣ **自訂記憶體管理**
需要精細控制記憶體生命週期時:
```c
typedef struct {
int id;
char *name; // 指向堆記憶體
} Person;
Person p;
p.name = malloc(50 * sizeof(char)); // 獨立分配字串空間
strcpy(p.name, "張三");
// 釋放時需先釋放內部成員
free(p.name);
```
---
### ⚠️ 重要注意事項
1. **必須檢查分配是否成功**
```c
int *arr = malloc(1000000 * sizeof(int));
if (arr == NULL) {
perror("記憶體分配失敗");
exit(EXIT_FAILURE);
}
```
2. **記憶體洩漏(Memory Leak)**
```c
void leaky() {
int *tmp = malloc(100 * sizeof(int));
// 忘記 free(tmp) → 每次呼叫洩漏 400 bytes
}
```
- 解決方案:使用 Valgrind 等工具檢測
3. **懸空指標(Dangling Pointer)**
```c
int *ptr = malloc(sizeof(int));
free(ptr);
*ptr = 10; // 危險!已釋放的記憶體
```
- 解決方案:釋放後立即設為 NULL
```c
free(ptr);
ptr = NULL;
```
---
### 🔄 替代方案比較
| 方法 | 生命週期 | 適用場景 |
|---------------|----------------|----------------------------|
| `malloc` | 手動控制 | 動態大小、跨函數存活 |
| 自動變數 | 函數結束時銷毀 | 小型臨時變數 |
| 全域/靜態變數 | 程式結束時銷毀 | 少量長期使用的資料 |
---
### 💡 最佳實踐
1. **分配與釋放對稱**
```c
void safe_use() {
Resource *res = malloc(sizeof(Resource));
init_resource(res);
// ... 使用資源 ...
cleanup(res); // 釋放內部資源
free(res); // 釋放主結構
}
```
2. **優先使用 `calloc` 初始化**
```c
// malloc 不初始化,calloc 初始化為0
int *zeros = calloc(100, sizeof(int));
```
3. **複雜結構使用分層釋放**
```c
typedef struct {
char *name;
int *scores;
} Student;
void free_student(Student *s) {
free(s->name); // 先釋放成員
free(s->scores);
free(s); // 再釋放主結構
}
```
---
### 🚫 何時避免使用
- 小型臨時變數 → 用自動變數(棧分配更快)
- 固定大小的陣列 → 用靜態陣列(更安全)
- 極高即時性需求場景 → 考慮靜態分配
> **關鍵總結**:`malloc` 用於需要動態控制記憶體生命週期和大小的場景,但需嚴防洩漏和非法存取。理解堆/棧差異是 C 語言進階的關鍵!
コメント