本專案為課堂限時練習產出,功能為選單選擇運算類型,隨機生成一道題目並可選擇看答案或下一題。程式碼雖能跑通,但存在 goto 濫用、隨機種子缺失、範圍未控、結構混亂等問題。本文提供原始碼、問題分析與重構版本。
#include <stdio.h>
#include <stdlib.h>
int main() {
int a,b,op,os;
printf("[每課一練 媽媽再也不用擔心我的學習]\n");
aq1: printf("選擇您想挑戰的運算法則\n");
printf("1.加法 2.減法 3.乘法 4.除法\n");
scanf("%d",&op);
switch(op) {
aq: case 1:
a=rand(); b=rand();
printf("題目:%d + %d = ?\n\n",a,b);
printf("1.看答案 2.下一題\n");
scanf("%d",&os);
if(os==1) { printf("%d + %d =%d\n\n\n",a,b,a+b); goto aq1; }
else goto aq;
break;
at: case 2:
a=rand(); b=rand();
printf("題目:%d - %d = ?\n\n",a,b);
printf("1.看答案 2.下一題\n");
scanf("%d",&os);
if(os==1) { printf("%d - %d =%d\n\n\n",a,b,a-b); goto aq1; }
else goto at;
break;
aq2: case 3:
a=rand(); b=rand();
printf("題目:%d * %d = ?\n\n",a,b);
printf("1.看答案 2.下一題\n");
scanf("%d",&os);
if(os==1) { printf("%d * %d =%d\n\n\n",a,b,a*b); goto aq1; }
else goto aq2;
break;
aq3: case 4:
a=rand(); b=rand();
printf("題目:%d / %d = ?\n\n",a,b);
printf("1.看答案 2.下一題\n");
scanf("%d",&os);
if(os==1) { printf("%d / %d =%d\n\n\n",a,b,a/b); goto aq1; }
else goto aq3;
break;
}
return 0;
}
| 問題 | 影響 | 修正方案 |
|---|---|---|
缺 srand() | 每次執行產生相同題目 | 開頭加 srand(time(NULL)) |
rand() 無範圍 | 數值過大 (0~32767),不適合國小 | rand()%100+1 限制 1~100 |
大量 goto | 程式結構混亂,難維護 | 改用 do-while 迴圈 + 函式 |
| 除法無整除保護 | 產生非整數答案 | 調整被除數為除數倍數 |
| 減法無序保護 | 可能出現負數答案 | 確保被減數 ≥ 減數 |
| 無退出機制 | 選單無 0 選項,只能強制結束 | 加入 case 0: break 並外層迴圈 |
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void show_menu() {
printf("\n=== 四則運算練習 ===\n");
printf("1.加法 2.減法 3.乘法 4.除法 0.結束\n選擇:");
}
int generate_question(int op, int *a, int *b, char *symbol) {
*a = rand()%100+1; *b = rand()%100+1;
switch(op) {
case 1: *symbol='+'; break;
case 2: *symbol='-'; if(*a<*b){int t=*a;*a=*b;*b=t;} break;
case 3: *symbol='*'; break;
case 4: *symbol='/'; if(*b==0)*b=1; *a=*a**b; break;
default: return 0;
}
return 1;
}
int main() {
srand((unsigned)time(NULL));
int choice, a, b, ans, correct;
char sym;
do {
show_menu();
if(scanf("%d",&choice)!=1) break;
if(choice==0) break;
if(choice<1 || choice>4) continue;
generate_question(choice, &a, &b, &sym);
printf("%d %c %d = ", a, sym, b);
scanf("%d", &ans);
switch(choice) {
case 1: correct=a+b; break;
case 2: correct=a-b; break;
case 3: correct=a*b; break;
case 4: correct=a/b; break;
}
if(ans==correct) printf("正確!\n");
else printf("錯誤,正確答案:%d\n", correct);
} while(choice!=0);
printf("再見!\n");
return 0;
}
goto,使用 do-while 控制流程從 v1.0 到 v2.0 的演進,展示了「先跑通、再重構」的務實開發態度,也是從初學者邁向工程師的關鍵一步。