#include <stdio.h>
void main() {
int i;
int f[5] = {1, 1}; // 只有 f[0], f[1] 顯式初始化為 1,其餘 f[2]~f[4] 隱式初始化為 0
for (i = 2; i <= 5; i++) // 錯誤 1: 循環條件 i<=5 導致訪問 f[5] 越界 (有效下標 0~4)
f[i] = f[i-2] + f[i-1]; // 錯誤 2: f[5] 寫入越界,破壞棧幀
for (i = 0; i <= 5; i++) { // 錯誤 3: 同樣越界讀取 f[5]
if (i % 5 == 0) printf("\n");
printf("%12d", f[i]);
}
printf("\n");
}
int f[5] 分配 5 個 int,合法下標 0, 1, 2, 3, 4。i <= 5 會執行 i = 2,3,4,5 四次,f[5] 寫入越界 (緩衝區溢出),行為未定義 (UB)。i <= 5 同樣讀取 f[5] 越界。若修正為 int f[6] 或循環 i < 5 (配合 f[5]):
f[0] = 1
f[1] = 1
i=2: f[2] = f[0] + f[1] = 1 + 1 = 2
i=3: f[3] = f[1] + f[2] = 1 + 2 = 3
i=4: f[4] = f[2] + f[3] = 2 + 3 = 5
i=5: f[5] = f[3] + f[4] = 3 + 5 = 8 // 需 f[6] 容納
輸出前 6 項 (下標 0~5):1 1 2 3 5 8。
for (i = 0; i <= 5; i++) {
if (i % 5 == 0) printf("\n"); // i=0,5 時換行
printf("%12d", f[i]); // 每個數佔 12 寬度右對齊
}
輸出樣式:
1 1 2 3 5
8
#include <stdio.h>
int main(void) {
const int N = 10; // 計算前 N 項
int f[N];
f[0] = 1;
f[1] = 1;
for (int i = 2; i < N; ++i) // 正確邊界: i < N
f[i] = f[i-2] + f[i-1];
for (int i = 0; i < N; ++i) {
if (i % 5 == 0) putchar('\n'); // 每 5 個換行
printf("%12d", f[i]);
}
putchar('\n');
return 0;
}
| 知識點 | 錯誤認知 | 正確理解 |
|---|---|---|
| 數組下標 | 以為 f[5] 是第 5 個元素 | f[5] 是第 6 個元素,f[0] 是第 1 個,f[n-1] 是第 n 個 |
| 循環邊界 | 習慣寫 i<=n | C 語言慣用半開區間 [0, n),循環條件 i < n |
| 越界後果 | 以為會報錯 | C 不做邊界檢查,越界屬 UB,可能沉默破壞數據/棧/返回地址,極難調試 |
| 隱式初始化 | 以為未初始化是隨機值 | 部分初始化的數組,剩餘元素保證為 0 (靜態/全局/局部靜態均如此) |
| main 返回類型 | void main() | 標準要求 int main(void) 或 int main(int argc, char *argv[]) |
第 93 項超過 unsigned long long (2^64-1)。需實現高精度加法 (數組/鏈表存十進制位) 或使用 GMP 庫。
// 高精度斐波那契框架 (十進制位數組,低位在前)
#define MAX_DIGITS 1000
void add_big(int *res, const int *a, const int *b, int len) {
int carry = 0;
for (int i = 0; i < len; ++i) {
int sum = a[i] + b[i] + carry;
res[i] = sum % 10;
carry = sum / 10;
}
// 處理最高位進位...
}
原代碼核心問題是 數組大小 5 與循環上限 5 不匹配導致越界。C 語言數組零基址、半開區間 [0, n) 是肌肉記憶級基本功。斐波那契遞推邏輯本身正確,修正邊界並擴大數組即可得到預期輸出 1 1 2 3 5 8。養成 -Wall -Wextra -fsanitize=address 編譯習慣,能在編譯/運行期捕獲 90% 以上越界錯誤。