表达式后面加个分号就成了语句:a = x + 1;、func();。没有副作用的表达式语句(比如孤零零的 x + 1;)毫无意义,编译器通常直接优化掉。用 {} 把多条语句包成一个代码块,在语法上等价于一条语句——所以 if、for 的主体想写多行就加花括号。
;(如 for(...);)会让循环体变成空语句——循环白跑。if (x > 0)
printf("positive\n");
else if (x == 0)
printf("zero\n");
else
printf("negative\n");
switch (ch) {
case 'a':
case 'e': /* case 落空即共用:元音一起处理 */
printf("vowel\n");
break;
case '0': case '1': /* 数字字符 */
printf("digit char\n");
break;
default:
printf("other\n");
break;
}switch 的三条硬规则:① 条件必须是整型表达式(浮点、字符串不行);② case 是常量且必须唯一;③ 不 break 就会「贯穿」到下一个 case。贯穿偶尔有用(如上面积累多个 case),但绝大多数时候是漏写 break 的事故——所以每个 case 末尾写 break、实在不需要的加注释说明,是好习惯。
| 循环 | 先判断? | 适用场景 |
|---|---|---|
| while (cond) body | 先判断 | 只知道「继续条件」,不知道次数:读输入、链表遍历 |
| for (init; cond; step) | 先判断 | 已知次数或有明确步进;init/step 可留空 |
| do body while (cond); | 后判断 | 至少执行一次:菜单循环、重试逻辑 |
int ch;
while ((ch = getchar()) != EOF) /* 赋值的值作为条件:惯用法 */
putchar(ch);
for (int i = 0; i < n; i++) { /* C99 起 init 里可声明变量 */
if (buf[i] == '\0') break; /* 提前终止 */
if (buf[i] == ' ') continue; /* 跳过本次,直接到 step */
process(buf[i]);
}break 跳出最近的一层循环或 switch;continue 只结束本轮、跳到步进/条件判断。它们都只影响最内层——想从两层循环里出来,要么加标志位,要么干脆封装成函数用 return。
goto 能跳到同函数内任意标签处。破坏结构化、难审查,日常代码不该用它。唯二还站得住脚的场景:
/* 1) 深层循环一次跳出 */
for (i = 0; i < N; i++)
for (j = 0; j < M; j++)
if (found(i, j))
goto done;
done:
report_result();
/* 2) 错误集中清理:失败统一跳 cleanup(free(NULL) 无害,正好复用) */
p1 = malloc(A); if (p1 == NULL) goto cleanup;
p2 = malloc(B); if (p2 == NULL) goto cleanup;
/* ... 使用 p1/p2 ... */
cleanup:
free(p2);
free(p1);