C語言學習筆記(二):運算符優先級、流程控制結構與經典案例
本文系統整理 C 語言基本運算(算術、關係、邏輯、位運算)優先級規則,以及三大程序結構(順序、選擇、循環)的語法細節與常見陷阱,附帶經典練習案例。
一、運算符優先級與結合性速查表
| 優先級 | 運算符 | 說明 | 結合性 |
| 1 (最高) | () [] -> . | 函數調用、下標、成員訪問 | 左→右 |
| 2 | ! ~ ++ -- +(正) -(負) *&(地址) sizeof (類型) | 一元運算符 | 右→左 |
| 3 | * / % | 乘除模 | 左→右 |
| 4 | + - | 加減 | 左→右 |
| 5 | < < > > | 移位 | 左→右 |
| 6 | < <= > >= | 關係比較 | 左→右 |
| 7 | == != | 相等性 | 左→右 |
| 8 | & | 按位與 | 左→右 |
| 9 | ^ | 按位異或 | 左→右 |
| 10 | | | 按位或 | 左→右 |
| 11 | && | 邏輯與 | 左→右 |
| 12 | || | 邏輯或 | 左→右 |
| 13 | ?: | 三目條件 | 右→左 |
| 14 | = += -= *= /= %= &= ^= |= <<= >>= | 賦值 | 右→左 |
| 15 (最低) | , | 逗號運算符 | 左→右 |
二、關鍵運算細節
1. 整數除法與取模
7 / 2 = 3,7 % 2 = 1
- 取模運算元必須為整數
-7 % 3 = -1(C99 標準:結果符號與被除數同號)
2. 自增自減陷阱
int a = 5;
int b = a++; // b=5, a=6 (後置:先用後增)
int c = ++a; // a=7, c=7 (前置:先增後用)
// 未定義行為:同一序列點多次修改同一變量
// int x = 5; int y = x++ + x++; // UB!
3. 邏輯運算短路特性
expr1 && expr2:expr1 為假(0) → 直接結束,expr2 不執行
expr1 || expr2:expr1 為真(非0) → 直接結束,expr2 不執行
- 利用短路保護:
if (p != NULL && p->val > 0)
4. sizeof 運算符
- 編譯時計算類型/表達式佔用字節數
sizeof(int) 需括號;sizeof x 變量可省略括號
sizeof(arr) 得到整個數組大小(不退化為指針)
三、流程控制結構
1. if-else 選擇結構
switch (expr) { // expr 必須為整型
case const1: stmts1; break;
case const2: stmts2; break;
default: stmts_def;
}
case 標籤必須為整型常量表達式
- 無
break 會「貫穿」執行下一 case
case 中定義變量需加 {} 限制作用域
3. 循環結構對比
| 循環類型 | 語法 | 判斷時機 | 至少執行次數 | 典型場景 |
| while | while(expr) stmt | 前置 | 0 | 未知次數,先檢查條件 |
| do-while | do stmt while(expr); | 後置 | 1 | 菜單交互、至少一次業務 |
| for | for(init; cond; step) stmt | 前置 | 0 | 已知次數、計數器控制 |
for 循環執行流程
for (init; cond; step) body;
// 等價於:
init;
while (cond) {
body;
step;
}
break / continue 語義
break:跳出最近一層循環或 switch
continue:跳過本次循環剩餘部分,直接進入下一次迭代判斷
- 嵌套循環中只影響內層
四、經典練習案例
案例 1:統計輸入行字符數
int count = 0;
char ch;
scanf("%c", &ch); // 讀首字符
while (ch != '\n') { // 非換行繼續
count++;
scanf("%c", &ch); // 讀下一字符
}
printf("count = %d\n", count);
案例 2:WASD 控制移動方向
char ch; int flag = 0;
printf("w:上 s:下 a:左 d:右 q:退出\n");
while (!flag) {
scanf("%c", &ch);
switch (ch) {
case 'w': case 'W': printf("上\n"); break;
case 's': case 'S': printf("下\n"); break;
case 'a': case 'A': printf("左\n"); break;
case 'd': case 'D': printf("右\n"); break;
case 'q': case 'Q': printf("退出\n"); flag = 1; break;
}
}
案例 3:猜數字遊戲 (1-1000, 10 次機會)
#include // arc4random_uniform (BSD/macOS) 或 rand()
int target = arc4random_uniform(1000) + 1; // 1-1000
// 通用公式:[m, n] → arc4random_uniform(n-m+1) + m
for (int attempt = 1; attempt <= 10; attempt++) {
int guess; scanf("%d", &guess);
if (guess > target) printf("大了\n");
else if (guess < target) printf("小了\n");
else { printf("恭喜!第%d次猜中\n", attempt); break; }
}
五、ASCII 碼應用
'0'=48, 'A'=65, 'a'=97
- 大小寫轉換:
c + 32 或 c | 0x20(大→小),c & 0xDF(小→大)
- 數字字符轉整數:
ch - '0'
六、總結建議
- 熟記優先級表前 8 級,其餘查表即可
- 複雜表達式加括號,可讀性優於炫技
- 邊界條件測試:0、1、最大值、空輸入
- 循環變量作用域儘量縮小(C99
for (int i=0; ...))
- 多寫、多調試、多看編譯器警告(
-Wall -Wextra)
- 上一篇文章: VCC 形式化驗證入門:Assertion 注釋與驗證原理
- 下一篇文章: 單片機 C 語言實現秒表:定時器中斷 + 外部中斷按鍵控制
Copyright ©
程式碼之家 All Rights Reserved