æ¡ä»¶åˆ¤æ–与循环控制
è¿™ä¸€å‘¨ä½ ä¼šè®©ç¨‹åºçœŸæ£â€œåŠ¨èµ·æ¥â€ï¼šä¼šåˆ¤æ–ã€ä¼šåˆ†æ”¯ã€ä¼šé‡å¤æ‰§è¡Œã€‚å…³é”®æ˜¯æ¯æ¡é€»è¾‘路径都清楚ã€å¯éªŒè¯ã€‚
å¦å®Œè¿™å‘¨ï¼Œä½ èƒ½æŠŠçŽ°å®žè§„åˆ™ç¿»è¯‘æˆ `if/else`ã€`switch`ã€`for`ã€`while`,并能自己排查æ»å¾ªçŽ¯å’Œåˆ†æ”¯é”™è¯¯ã€‚
5.1 å¦ä¹ é‡ç‚¹
先练分支,å†ç»ƒå¾ªçŽ¯ï¼Œæœ€åŽåšç»„åˆç»ƒä¹ 。拆开è®ç»ƒæ›´å®¹æ˜“å‘现问题,也更容易稳定进æ¥ã€‚
5.2 æ¡ä»¶åˆ¤æ–
`if/else` 适åˆèŒƒå›´åˆ¤æ–,`switch` 适åˆå›ºå®šé€‰é¡¹ã€‚写æ¡ä»¶æ—¶æ³¨æ„边界,`>= 60` å’Œ `> 60` 会得到ä¸åŒç»“论。
int score = 78;
if (score >= 90) {
cout << "A\n";
} else if (score >= 75) {
cout << "B\n";
} else if (score >= 60) {
cout << "C\n";
} else {
cout << "D\n";
}
5.3 循环控制
`for` 常用于次数明确的任务,`while` 常用于æ¡ä»¶é©±åŠ¨ä»»åŠ¡ã€‚å¾ªçŽ¯ä»£ç 一定è¦å…ˆç¡®è®¤é€€å‡ºæ¡ä»¶ï¼Œé¿å…塿»ã€‚
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
cout << "1 到 100 的和: " << sum << "\n";
5.4 分支 + 循环组åˆ
ç»„åˆæ—¶å»ºè®®â€œå…ˆå¾ªçŽ¯ï¼Œå†åœ¨å¾ªçŽ¯ä½“å†…åˆ¤æ–â€ã€‚例如批é‡å¤„ç†æˆç»©æ—¶ï¼Œå…ˆé历æ¯ä¸ªæˆç»©ï¼Œå†åˆ¤æ–是å¦åˆæ³•。
vector<int> scores = {95, 82, -1, 76, 120, 60};
int validCount = 0;
for (int s : scores) {
if (s < 0 || s > 100) {
cout << "éžæ³•分数: " << s << "\n";
continue;
}
validCount++;
}
cout << "åˆæ³•分数数é‡: " << validCount << "\n";
5.5 深度讲解:æ¡ä»¶åˆ†æ”¯å¦‚何写得稳定
判æ–è¯å¥æœ€å¸¸è§çš„é—®é¢˜ä¸æ˜¯â€œä¸ä¼šå†™â€ï¼Œè€Œæ˜¯â€œå†™å‡ºæ¥ä»¥åŽéšè— bug 很多â€ã€‚æ¯”å¦‚ä½ åœ¨æˆç»©åˆ¤æ–里先写了 `if (score >= 60)`,åŽé¢å†å†™ `else if (score >= 90)`,那 `>= 90` 永远ä¸ä¼šè§¦å‘ï¼Œå› ä¸ºå‰é¢çš„æ¡ä»¶å·²ç»æŠŠå®ƒæ‹¦æˆªäº†ã€‚è¿™ä¸ªé”™è¯¯åœ¨åˆå¦é˜¶æ®µéžå¸¸å¸¸è§ï¼ŒåŽŸå› æ˜¯åŒå¦åªå…³æ³¨å•æ¡æ¡ä»¶ï¼Œä¸å…³æ³¨æ¡ä»¶ä¹‹é—´çš„顺åºå…³ç³»ã€‚å»ºè®®ä½ æŠŠåˆ†æ”¯å½“æˆâ€œä»Žä¸Šåˆ°ä¸‹çš„ç›é€‰å™¨â€ï¼Œå…ˆç›æœ€ä¸¥æ ¼æ¡ä»¶ï¼Œå†ç›å®½æ¾æ¡ä»¶ã€‚æŽ’åºæ£ç¡®åŽï¼Œåˆ†æ”¯é€»è¾‘就会稳定很多。
第二个高频问题是边界é‡å æˆ–ç©ºæ´žã€‚æ¯”å¦‚ä½ å†™ `if (x > 0 && x < 10)`,`else if (x > 10 && x < 20)`,那 `x == 10` 会è½åˆ°å“ªé‡Œï¼Ÿå¦‚æžœä½ æ²¡æœ‰æ˜¾å¼è¦†ç›–ï¼Œå®ƒå°±ä¼šæŽ‰è¿›æ„æ–™ä¹‹å¤–的分支。写æ¡ä»¶æ—¶å»ºè®®å…ˆåœ¨çº¸ä¸Šåˆ—出关键边界值:最å°å€¼ã€æœ€å¤§å€¼ã€ä¸´ç•Œå€¼ã€‚ç„¶åŽé€ä¸ªä»£å…¥æ¯æ¡æ¡ä»¶ï¼Œç¡®è®¤æ¯ä¸ªå€¼éƒ½èƒ½è½åˆ°æ£ç¡®åˆ†æ”¯ã€‚这个动作éžå¸¸ç®€å•,但能一次性å‘现大é‡é€»è¾‘æ¼æ´žã€‚
第三个问题是æ¡ä»¶å¯è¯»æ€§ã€‚很多åŒå¦å–œæ¬¢æŠŠå¤æ‚é€»è¾‘ä¸€å£æ°”写进 `if`,结果自己两天åŽéƒ½çœ‹ä¸æ‡‚。比如 `if ((a>0&&b<5)||(!flag&&c==3)||...)` è¿™ç§å†™æ³•å¯è¿è¡Œï¼Œä½†ä¸åˆ©äºŽç»´æŠ¤ã€‚更推èåšæ³•是把æ¡ä»¶æ‹†æˆæœ‰æ„义的布尔å˜é‡ï¼š`bool isValidAge`ã€`bool hasPermission`ã€`bool isTimeAllowed`,最åŽå†ç»„åˆåˆ¤æ–。å¯è¯»æ€§ä¸æ˜¯â€œé”¦ä¸Šæ·»èбâ€ï¼Œå®ƒç›´æŽ¥å†³å®šä½ 调试速度和å作效率。
5.6 深度讲解:循环边界ã€ç»ˆæ¢æ¡ä»¶ä¸Žæ€§èƒ½æ„识
å¾ªçŽ¯æŽ§åˆ¶çš„æ ¸å¿ƒæ˜¯ä¸‰ä»¶äº‹ï¼šä»Žå“ªé‡Œå¼€å§‹ã€æ‰§è¡Œå¤šå°‘次ã€ä½•时结æŸã€‚任何一个点模糊,程åºå°±å®¹æ˜“出错。比如 `for (int i = 0; i <= n; i++)` 与 `for (int i = 0; i < n; i++)` 的差别是是å¦å¤šæ‰§è¡Œä¸€æ¬¡ã€‚这个“+1/-1â€é”™è¯¯åœ¨æ•°ç»„访问ä¸å°¤å…¶å±é™©ï¼Œå› 为它å¯èƒ½å¯¼è‡´è¶Šç•Œè®¿é—®ã€‚ä½ å¯ä»¥ç»™è‡ªå·±ä¸€ä¸ªå›ºå®šåŠ¨ä½œï¼šå†™å®Œå¾ªçŽ¯åŽå…ˆå£å¤´è¯»ä¸€é“i ä»Žå‡ åˆ°å‡ ï¼Œæ€»å…±è·‘å‡ æ¬¡â€ï¼Œç¡®è®¤å’Œé¢˜ç›®ä¸€è‡´å†è¿è¡Œã€‚
在 `while` 循环里,最容易å‘生的是忘记更新状æ€ã€‚比如读å–ç”¨æˆ·è¾“å…¥åŽæ²¡æœ‰æ›´æ–°å˜é‡ï¼Œç¨‹åºå°±ä¼šä¸€ç›´åœåœ¨æ—§æ¡ä»¶é‡Œã€‚è§£å†³åŠžæ³•æ˜¯æŠŠâ€œçŠ¶æ€æ›´æ–°è¯å¥â€æ”¾åœ¨ä½ 一眼就能看到的ä½ç½®ï¼Œä¸è¦åŸ‹åœ¨å¤æ‚分支深处。还有一个实用技巧:在调试阶段打å°å¾ªçŽ¯è½®æ¬¡å’Œå…³é”®å˜é‡å€¼ï¼Œä¾‹å¦‚ `cout << "round=" << round << ", hp=" << hp << "\n";`ã€‚è¿™èƒ½è®©ä½ å¿«é€Ÿçœ‹è§ç¨‹åºæ˜¯å¦åœ¨å‘ç»ˆæ¢æ¡ä»¶é 近。
å¦å¤–ï¼Œä½ å¯ä»¥åœ¨æœ¬å‘¨å¼€å§‹å»ºç«‹æœ€åŸºç¡€çš„æ€§èƒ½æ„识:é‡å¤è®¡ç®—èƒ½å¦æå‰ç¼“å˜ï¼Ÿå¾ªçŽ¯é‡Œæ˜¯å¦æœ‰ä¸å¿…è¦çš„ IO 输出?例如æŸäº›å¸¸é‡å¯ä»¥æ”¾åˆ°å¾ªçŽ¯å¤–ï¼Œé¿å…æ¯æ¬¡é‡å¤è®¡ç®—。虽然当å‰é¡¹ç›®è§„模还å°ï¼Œä½†è¿™ä¸ªæ€ç»´ä¼šåœ¨åŽç»å¤§åž‹é¡¹ç›®é‡Œå¸®ä½ 节çœå¾ˆå¤šæ—¶é—´ã€‚请记ä½ï¼šå…ˆä¿è¯æ£ç¡®ï¼Œå†è€ƒè™‘效率;但在ä¿è¯æ£ç¡®çš„å‰æä¸‹ï¼Œå†™å‡ºç»“æž„æ¸…æ¥šçš„å¾ªçŽ¯ï¼Œæœ¬èº«å°±æ˜¯æ•ˆçŽ‡ä¼˜åŒ–çš„ä¸€éƒ¨åˆ†ã€‚
int n = 0;
cout << "请输入è¦å¤„ç†çš„æ•°æ®ä¸ªæ•°: ";
cin >> n;
if (n <= 0) {
cout << "个数必须大于 0。\n";
return 0;
}
int valid = 0;
for (int i = 0; i < n; i++) {
int score = 0;
cin >> score;
if (score < 0 || score > 100) continue;
valid++;
}
cout << "åˆæ³•æ•°æ®æ•°é‡: " << valid << "\n";
5.7 å¦ä¹ ç–略:用“路径测试â€éªŒè¯æŽ§åˆ¶æµ
这一周特别推èä½ ä½¿ç”¨â€œè·¯å¾„æµ‹è¯•â€æ–¹æ³•。路径测试的æ€è·¯æ˜¯ï¼šä¸æ˜¯åªçœ‹æœ€ç»ˆç»“果,而是确认æ¯ä¸€æ¡åˆ†æ”¯è·¯å¾„都至少走过一次。比如èœå•计算器有 1 到 5 äº”ä¸ªé€‰é¡¹ï¼Œä½ å°±è‡³å°‘å‡†å¤‡äº”ç»„è¾“å…¥ï¼Œè®©æ¯ä¸ªé€‰é¡¹éƒ½è¢«è§¦å‘。若æŸä¸ªåˆ†æ”¯ä»Žæœªè¢«æ‰§è¡Œï¼Œä½ å°±æ— æ³•è¯æ˜Žå®ƒæ£ç¡®ã€‚很多线上 bug 都æ¥è‡ªâ€œé€»è¾‘写了但从没测过â€ã€‚
ä½ è¿˜å¯ä»¥åšä¸€ä»½ç®€åŒ–测试表:输入ã€é¢„计进入分支ã€é¢„期输出ã€å®žé™…è¾“å‡ºã€æ˜¯å¦ä¸€è‡´ã€‚è¿™ä¸ªè¡¨æ ¼çœ‹èµ·æ¥åƒâ€œé¢å¤–工作â€ï¼Œå…¶å®žæ˜¯ä½ è¿›æ¥æœ€å¿«çš„å·¥å…·ã€‚å› ä¸ºå®ƒæŠŠâ€œæˆ‘æ„Ÿè§‰ç¨‹åºå·®ä¸å¤šå¯¹äº†â€å˜æˆâ€œæˆ‘æœ‰è¯æ®è¯´æ˜Žç¨‹åºæ£ç¡®â€ã€‚é•¿æœŸåšæŒåŽï¼Œä½ 会形æˆéžå¸¸å¼ºçš„工程æ€ç»´ï¼šå…ˆå®šä¹‰è¡Œä¸ºï¼Œå†éªŒè¯è¡Œä¸ºï¼Œæœ€åŽæ‰å‘布结果。
æœ€åŽæé†’ä¸€ç‚¹ï¼šä¸è¦æƒ§æ€•釿ž„。å‘现分支太乱ã€å¾ªçŽ¯å¤ªæ·±æ—¶ï¼Œå‹‡æ•¢æ‹†å‡½æ•°ã€æ‹†å˜é‡ã€æ‹†æ¥éª¤ã€‚代ç 䏿˜¯ä¸€æ¬¡å†™å®Œä¸åŠ¨çš„ä½œæ–‡ï¼Œè€Œæ˜¯å¯ä»¥æŒç»è¿ä»£çš„ç³»ç»Ÿã€‚ä½ åœ¨ç¬¬äºŒé˜¶æ®µå…»æˆçš„æ¯ä¸ªå¥½ä¹ æƒ¯ï¼Œéƒ½ä¼šåœ¨åŽç»é¡¹ç›®é‡Œæ”¾å¤§æ”¶ç›Šã€‚
5.8 è¯¾å ‚é—®ç”与进阶练ä¹
问:`if` å’Œ `switch` 怎么选? 如果是范围判æ–(例如分数区间ã€è¡€é‡é˜ˆå€¼ï¼‰ï¼Œä¼˜å…ˆ `if/else`;如果是固定枚举(例如èœå•选项 1 到 5),优先 `switch`ã€‚é€‰æ‹©æ ‡å‡†ä¸æ˜¯â€œå“ªç§æ›´é…·â€ï¼Œè€Œæ˜¯â€œå“ªç§æ›´å®¹æ˜“读懂和维护â€ã€‚å†™å›¢é˜Ÿä»£ç æ—¶ï¼Œå¯è¯»æ€§æ°¸è¿œä¼˜å…ˆã€‚
问:为什么我总是出现æ»å¾ªçŽ¯ï¼Ÿ å› ä¸ºå¾ªçŽ¯å˜é‡æ²¡æœ‰æŒ‰é¢„期å˜åŒ–,或者退出æ¡ä»¶æ°¸è¿œä¸ä¼šæˆç«‹ã€‚最实用的办法是打å°â€œè½®æ¬¡ + 关键å˜é‡â€ï¼Œä¾‹å¦‚ `round`ã€`choice`ã€`hp`ï¼Œè§‚å¯Ÿå®ƒä»¬æ˜¯å¦æœç»ˆæ¢æ–¹å‘å˜åŒ–。åªè¦å˜é‡ä¸å˜ï¼Œå¾ªçޝ就ä¸å¯èƒ½ç»“æŸã€‚è¿™ä¸ªå®šä½æ€è·¯æ¯”盲改代ç 高效得多。
问:怎么判æ–循环边界写对了? 先用一å¥è¯è¯´æ¸…â€œåº”è¯¥æ‰§è¡Œå‡ æ¬¡â€ï¼Œå†å推边界表达å¼ã€‚æ¯”å¦‚â€œå¤„ç† 10 ä¸ªå…ƒç´ â€ï¼Œé€šå¸¸å†™ `i = 0` 到 `i < 10`。然åŽç”¨æœ€å°æ ·ä¾‹éªŒè¯ï¼Œä¾‹å¦‚åªç»™ 1 ä¸ªå…ƒç´ ï¼Œçœ‹å¾ªçŽ¯æ˜¯å¦æ°å¥½è·‘ 1 次。这个方法对 `for` 和数组é历尤其有效。
è¿›é˜¶ç»ƒä¹ å»ºè®®ï¼šå®žçŽ°â€œå…³å¡ç»“算器â€ã€‚输入玩家æ¯å…³å¾—分,程åºå¾ªçŽ¯è¯»å–直到输入 `-1` 结æŸï¼Œç„¶åŽè¾“出总分ã€å¹³å‡åˆ†ã€æœ€é«˜åˆ†å’Œæœ€ä½Žåˆ†ï¼Œå¹¶æ ¹æ®å¹³å‡åˆ†ç»™å‡ºè¯„çº§ã€‚è¦æ±‚: ç¬¬ä¸€ï¼Œéžæ³•分数(å°äºŽ 0 且ä¸ç‰äºŽ -1,或大于 100)必须æç¤ºå¹¶å¿½ç•¥ï¼› 第二,至少用一个 `continue` 和一个 `break`ï¼› 第三,给出测试清å•,覆盖空输入ã€å…¨éžæ³•è¾“å…¥ã€æ£å¸¸æ··åˆè¾“入三ç§åœºæ™¯ã€‚
å»ºè®®ä½ æŠŠè¿™æ¬¡ä½œä¸šå½“æˆâ€œæŽ§åˆ¶æµèƒ½åŠ›éªŒæ”¶â€ï¼šä¸æ˜¯çœ‹ç¨‹åºæœ‰å¤šé•¿ï¼Œè€Œæ˜¯çœ‹æ¯æ¡è·¯å¾„是å¦å¯è§£é‡Šã€å¯å¤çްã€å¯éªŒè¯ã€‚åªè¦ä½ 能清楚说明“程åºä¸ºä»€ä¹ˆåœ¨è¿™ä¸ªè¾“入下走这æ¡è·¯â€ï¼Œå°±è¯´æ˜Žä½ çœŸæ£æŽŒæ¡äº†æ¡ä»¶ä¸Žå¾ªçŽ¯ã€‚
5.9 æœ¬å‘¨ç»ƒä¹ ä¸Žè‡ªæµ‹æ¸…å•
本周练ä¹
- 完æˆèœå•计算器(循环显示èœå•,支æŒå››åˆ™è¿ç®—与退出)。
- 补充“猜数å—â€å¾ªçŽ¯ç‰ˆå¹¶ç»Ÿè®¡å°è¯•次数。
- æäº¤è‡³å°‘ 6 组测试结果。
自测清å•
- æ¯ä¸ªåˆ†æ”¯æ˜¯å¦éƒ½è¢«æµ‹è¯•覆盖。
- å¾ªçŽ¯æ˜¯å¦æœ‰æ¸…晰退出æ¡ä»¶ã€‚
- é”™è¯¯è¾“å…¥æ˜¯å¦æœ‰æ˜Žç¡®æç¤ºã€‚
- 我能解释分支顺åºä¸ºä»€ä¹ˆè¿™æ ·å†™ã€‚
å¤ç›˜æ¨¡æ¿å»ºè®®ï¼šç¬¬ä¸€ï¼Œå†™å‡ºæœ¬å‘¨ä½ æœ€å®¹æ˜“æ¼æµ‹çš„ 3 æ¡è·¯å¾„ï¼›ç¬¬äºŒï¼Œä¸ºæ¯æ¡è·¯å¾„è¡¥ 1 组最å°è¾“入;第三,记录“错误现象 -> æ ¹å› -> ä¿®å¤åŠ¨ä½œ -> 防å¤å‘规则â€ã€‚åšæŒè¿™æ ·åšä¸¤åˆ°ä¸‰å‘¨ï¼Œä½ ä¼šæ˜Žæ˜¾æ„Ÿè§‰æŽ§åˆ¶æµ bug æ•°é‡ä¸‹é™ã€‚很多åŒå¦å¡åœ¨â€œä¼šå†™ä½†ä¸ç¨³â€ï¼Œæœ¬è´¨å°±æ˜¯ç¼ºå°‘系统å¤ç›˜ã€‚把å¤ç›˜å˜æˆå›ºå®šåŠ¨ä½œï¼Œä½ çš„ä»£ç è´¨é‡ä¼šä¸Šä¸€ä¸ªå°é˜¶ã€‚
é¢å¤–挑战:把èœå•计算器扩展æˆâ€œè¿žç»ä»»åŠ¡æ¨¡å¼â€ï¼Œå…许用户一轮内执行多次è¿ç®—并输出历å²è®°å½•ã€‚è¿™ä¸ªæŒ‘æˆ˜ä¼šè®©ä½ ç»ƒåˆ°å¾ªçŽ¯åµŒå¥—ã€çжæ€ç®¡ç†å’Œé€€å‡ºé€»è¾‘ï¼Œèƒ½å¾ˆå¥½æ£€éªŒä½ æ˜¯å¦çœŸæ£æŽŒæ¡æŽ§åˆ¶æµã€‚
错误案例æé†’ï¼šå¦‚æžœä½ å‘现æŸä¸ªåˆ†æ”¯â€œæ€»æ˜¯è¿›ä¸åŽ»â€ï¼Œå…ˆæ£€æŸ¥å®ƒå‰é¢çš„分支是å¦å·²æŠŠæ¡ä»¶è¦†ç›–;如果循环“跑ä¸å®Œâ€ï¼Œä¼˜å…ˆæ£€æŸ¥å˜é‡æ˜¯å¦åœ¨æ¯è½®æ£ç¡®æ›´æ–°ã€‚
æœ€åŽæé†’ï¼šæŽ§åˆ¶æµæ£ç¡®æ€§æ°¸è¿œæ¯”代ç 炫技更é‡è¦ã€‚