動態數組是 C 語言處理「運行時才知道大小」數據的核心技能。本文通過一個完整的交互式程序,演示 `malloc` 分配、`scanf` 填充、`free` 釋放的標準流程,並解析常見錯誤與最佳實踐。
#include <stdio.h>
#include <stdlib.h> // malloc, free 原型在此
int main(void) {
int len;
int *arr = NULL; // 良習:指針初始化為 NULL
printf("請輸入數組長度: ");
if (scanf("%d", &len) != 1 || len <= 0) {
fprintf(stderr, "無效長度\n");
return 1;
}
// 1. 分配內存:類型大小 * 元素個數
arr = (int *)malloc(len * sizeof(int));
if (arr == NULL) { // 必須檢查分配失敗
perror("malloc 失敗");
return 1;
}
// 2. 使用數組:與靜態數組完全一致
printf("請輸入 %d 個整數: ", len);
for (int i = 0; i < len; i++) {
if (scanf("%d", &arr[i]) != 1) {
fprintf(stderr, "輸入錯誤\n");
free(arr); // 提前退出也要釋放
return 1;
}
}
// 3. 遍歷輸出
for (int i = 0; i < len; i++) {
printf("%d:%d ", i, arr[i]);
}
printf("\n");
// 4. 釋放內存:防止內存洩漏
free(arr);
arr = NULL; // 良習:釋放後置 NULL,防野指針
return 0;
}
$ gcc dynamic_array.c -o dyn -std=c99
$ ./dyn
請輸入數組長度: 5
請輸入 5 個整數: 10 20 30 40 50
0:10 1:20 2:30 3:40 4:50
void *malloc(size_t size);
// 成功:返回分配內存起始地址(void*,需強轉)
// 失敗:返回 NULL
必須檢查返回值! 忽略檢查是導致段錯誤的首要原因。
永遠使用 `sizeof(類型) * 個數`,而非硬編碼字節數:
int *p = malloc(n * sizeof(int)); // 正確
double *d = malloc(n * sizeof(double)); // 正確
// 錯誤:int *p = malloc(n * 4); // 假設 int 4 字節,不可移植
int *new_arr = realloc(arr, new_len * sizeof(int));
if (new_arr == NULL) {
// 擴容失敗,原 arr 仍有效,需繼續使用或釋放
} else {
arr = new_arr; // 成功,更新指針
}
注意:`realloc` 可能移動內存塊,舊指針失效,必須用返回值更新。
| 錯誤代碼 | 後果 | 修正 |
|---|---|---|
| `int *p; p[0]=1;` | 野指針寫入,崩潰 | 先 malloc |
| `malloc(n*4);` | 不可移植 | `malloc(n*sizeof(int))` |
| 不檢查 malloc 返回值 | 後續解引用 NULL 崩潰 | 判空處理 |
| 忘記 free | 內存洩漏 | 配對 free |
| free 後繼續使用指針 | Use-after-free,未定義行為 | free 後置 NULL |
typedef struct {
int *data;
size_t size; // 當前元素數
size_t capacity; // 分配容量
} DynArray;
void dyn_init(DynArray *a) { a->data=NULL; a->size=0; a->capacity=0; }
void dyn_push(DynArray *a, int val) {
if (a->size == a->capacity) {
size_t new_cap = a->capacity ? a->capacity*2 : 4;
int *p = realloc(a->data, new_cap*sizeof(int));
if (!p) return; // 錯誤處理省略
a->data = p; a->capacity = new_cap;
}
a->data[a->size++] = val;
}
void dyn_free(DynArray *a) { free(a->data); dyn_init(a); }
動態數組 = `malloc` 分配 + 下標訪問 + `free` 釋放。掌握「檢查返回值、正確計算大小、配對釋放、釋放後置 NULL」四大鐵律,即可安全高效地在 C 語言中處理任意大小的數據集合。