8.3 字元的運算

字元骨子裡是整數,所以整數會的運算它都會——加減、比較都沒問題。把 char 想成「1 位元組的迷你整數」,只差在 cout 印它時會印出編號對應的字元而不是編號本身。這一節把競程用得到的字元運算一次練齊。

字母的位移與距離

「區段內連續」讓兩件事變得超簡單——往後數 k 個字母(加法)和算兩個字母差幾個位置(減法):

#include <iostream>
using namespace std;

int main() {
    char c1 = 'A';
    char c2 = c1 + 1;               // 'A' 的下一個字母
    cout << c2 << '\n';             // B

    cout << (char)('a' + 2) << '\n';  // 小寫同理:'a' 往後數 2 個 → c

    int dif = 'z' - 'a';            // 兩個字母的「距離」
    cout << dif << '\n';            // 25:z 是第 25 個小寫字母(從 0 數起)
    return 0;
}

執行結果:

B
c
25

數字字元同理:'1' + 5 對應到 '6'(嚴格說,運算的結果是整數)、'8' - '3'5。但注意運算範圍——數字字元只有 '0' ~ '9' 十個,加超過就掉出區段外:

#include <iostream>
using namespace std;

int main() {
    char c = '9';       // '9' 的編號是 57
    c++;
    cout << c << '\n';  // 編號 58 是冒號,不是「'10'」!
    return 0;
}

執行結果:

:

'9' 加一不會變成「一個代表 10 的字元」——ASCII 表上 57 的下一格是冒號 ':'。想做真正的十進位進位,得先 c - '0' 轉成數值再算。

大小寫轉換

同一個字母的大小寫編號差固定是 32,所以大寫加 32 變小寫、小寫減 32 變大寫。但更推薦的寫法是讓編譯器自己算差距——忘了 32 也不會錯:

#include <iostream>
using namespace std;

int main() {
    char c1 = 'A';
    char c2 = c1 + 32;              // 加上固定差距 32
    cout << c2 << '\n';             // a

    char c3 = 'c';
    char c4 = c3 + 'A' - 'a';       // 小寫轉大寫:加上(大寫 − 小寫)的差距
    cout << c4 << '\n';             // C

    char c5 = 'Q';
    char c6 = c5 + 'a' - 'A';       // 大寫轉小寫:方向反過來
    cout << c6 << '\n';             // q
    return 0;
}

執行結果:

a
C
q

記法:要變成誰,就把誰放前面加——轉小寫加 'a' - 'A',轉大寫加 'A' - 'a'。(8.5 還會介紹更省事的內建函式 touppertolower。)

一條一定要記的規則:integer promotion

用一個極端的例子感受一下——兩個「字元」相乘:

#include <iostream>
using namespace std;

int main() {
    cout << 'c' * '\n' << '\n';   // 'c' 是 99、'\n' 是 10,相乘就是整數運算
    return 0;
}

執行結果:

990

沒有任何錯誤訊息——字元本來就是整數,乘起來理直氣壯。規則本身不難,難的是它埋的陷阱:

動手試試看:輸入兩個大寫字母,輸出它們在字母表中相隔幾個位置(例如 AE 相隔 4)。誰前誰後不一定,記得用上冊 7.6abs 取絕對值。