#define N 2
int c[N] = {1, 2}, *pb; // ① 初始化列表 2 個元素,但下面 scanf 讀 N 個,邏輯矛盾
for (int i = 0; i < N; i++)
scanf("%d", &c[i]); // ② 覆蓋初始值,但提示「輸入一個數組」語意不清
int *f(int *a) {
int b[N]; // ③ 局部數組棧上分配
for (int i = 0; i < N; i++)
if (*(a+i) % 2 != 0)
b[i] = *(a+i); // ④ 未賦值元素留下垃圾值
return &b[0]; // ❌ 返回局部數組地址 → 未定義行為 (棧幀銷毀)
}
#include
#include
int *filter_odd(const int *src, size_t n, size_t *out_len) {
// 先計算奇數個數
size_t cnt = 0;
for (size_t i = 0; i < n; i++)
if (src[i] % 2 != 0) cnt++;
int *dst = malloc(cnt * sizeof(int));
if (!dst) return NULL;
size_t j = 0;
for (size_t i = 0; i < n; i++)
if (src[i] % 2 != 0)
dst[j++] = src[i];
*out_len = cnt;
return dst; // 堆內存,調用者負責 free
}
int main(void) {
size_t N;
printf("請輸入數組長度: ");
if (scanf("%zu", &N) != 1 || N == 0) return 1;
int *arr = malloc(N * sizeof(int));
if (!arr) return 1;
printf("請輸入 %zu 個整數 (空格分隔): ", N);
for (size_t i = 0; i < N; i++)
if (scanf("%d", &arr[i]) != 1) { free(arr); return 1; }
size_t out_len;
int *odd = filter_odd(arr, N, &out_len);
free(arr); // 原數組釋放
if (!odd) { puts("內存不足"); return 1; }
printf("奇數元素: ");
for (size_t i = 0; i < out_len; i++)
printf("%d ", odd[i]);
putchar('\n');
free(odd); // 釋放結果數組
return 0;
}
| 原錯誤 | 後果 | 修正方案 |
|---|---|---|
#define N 2 固定長度 | 無法處理任意長度輸入 | 運行時讀取長度,動態分配 |
局部數組 b[N] 返回地址 | 函數返回後棧內存無效,訪問崩潰/垃圾值 | 用 malloc 分配堆內存,或輸出參數填充調用者提供的緩衝區 |
未初始化 b[i] (偶數情況) | 結果數組含垃圾值 | 只存入奇數,或預先 memset,或用動態數組精確大小 |
宏 N 與變量名衝突風險 | 預處理器全局替換,易誤傷 | 宏名全大寫加前綴 ARR_MAX_LEN,或用 const size_t / enum |
// 返回實際寫入個數,緩衝區由調用者提供
size_t filter_odd_inplace(const int *src, size_t n, int *dst, size_t dst_cap) {
size_t j = 0;
for (size_t i = 0; i < n && j < dst_cap; i++)
if (src[i] % 2 != 0)
dst[j++] = src[i];
return j;
}
掌握「誰分配誰釋放」、「避免返回棧地址」、「動態數組三部曲 (malloc/使用/free)」是 C 語言內存管理鐵律。