8.1 字元的本質:ASCII 編碼
上冊 2.4 學過:char 型態存單一個字元,佔 1 位元組,用單引號寫('A'、'5'、'+')。當時留了一句話:「每個字元背後都有一個數字」——現在正式把這件事說完。
電腦的記憶體裡只有數字,沒有「字母」這種東西。所以電腦存字元的方法很直接:幫每個字元編一個號碼,存字元=存它的號碼。這張「字元 ↔ 號碼」的對照表就是 ASCII 編碼(American Standard Code for Information Interchange),它規定了編號 0 \sim 127 各對應到什麼字元。
這 128 個編號分成兩類:
- 可顯示字元(printable characters):編號 32 \sim 126,共 95 個——就是 2.4 數過的「大小寫字母 52 +數字 10 +標點符號 32 +空格 1」。空格(編號 32)雖然看不見,也算可顯示字元。
- 控制字元(control characters):編號 0 \sim 31 和 127,負責「動作」而不是「圖案」——最常見的是編號 10 的換行
'\n'和編號 9 的 Tab'\t'(上冊 2.4 的跳脫字元,就是用來寫出這些看不見的字元)。
¶三大區段:唯一需要記的重點
整張 ASCII 表不用背。競程裡其他字元也都會出現(例如網格題的 # 和 .、各種標點),但那些用到再查、直接拿字元比對就好;出場頻率最高、值得把編號規律記熟的,是這三個區段:
| 字元範圍 | ASCII 編號 | 個數 | 重點 |
|---|---|---|---|
'0' ~ '9' |
48 \sim 57 | 10 個 | 數字字元,編號連續遞增 |
'A' ~ 'Z' |
65 \sim 90 | 26 個 | 大寫字母,編號連續遞增 |
'a' ~ 'z' |
97 \sim 122 | 26 個 | 小寫字母,編號連續遞增 |
三件事比編號本身更重要:
- 區段內連續:
'B'的編號恰是'A'加 1,'7'恰是'0'加 7。這是下一節所有轉換技巧的地基。 - 區段的相對位置:數字 < 大寫 < 小寫。特別注意小寫字母的編號比大寫大——
'a'(97)比'Z'(90)還大。 - 大小寫的固定差距:同一個字母的小寫編號比大寫恰好大 32(
'a'= 97 = 65 + 32)。
編號實在忘了,回到本節這張表查就好;「連續」和「相對位置」這兩件事,才是需要放進腦子裡的。
¶範例程式碼
字元的比較,比的其實就是 ASCII 編號——這也解釋了 6.6 說「字元可以直接用 <、> 比較」的原因:
#include <iostream>
using namespace std;
int main() {
cout << ('A' < 'B') << '\n'; // 1:比的是編號,65 < 66
cout << ('5' < '9') << '\n'; // 1:數字字元也按編號排,53 < 57
cout << ('a' < 'A') << '\n'; // 0:小寫編號比大寫「大」,97 < 65 不成立
return 0;
}
執行結果:
1
1
0
第三行是很多人的直覺盲點:字典裡 a 排在最前面,但在 ASCII 裡 'a' 比 'Z' 大。之後遇到「把大小寫混在一起排序」的題目,這件事會決定答案的順序。
動手試試看:先用三大區段表猜下面三個比較的結果,再寫程式驗證:'0' < 'A'、'Z' < 'a'、'z' < '{'(最後一個超出三大區段,印出 (int)'{' 看看它的編號是多少)。