字元

極為常見

雖然在 基本資料型態 中我們有簡單提到字元,但我們其實還有很多東西沒有講到,所以這個章節我們就來更深入的了解一下字元!

所謂的字元就是指一個字,通常為符號、字母、數字還有換行字元等等,好比說 a1+\n

基本用法

在 C++ 中,字元的型態是 char,宣告方式如下,不過要記得所有的字元都要用單引號 ' 包住:

char c = 'a';

cout << c << endl; // a
注意

請不要使用雙引號 " 來包住字元,因為這樣會變成字串,而不是字元:

char c = "a"; // 這樣是錯誤的

關於字串的部分,我們會在之後的章節詳細介紹。

ASCII 編碼

在繼續學習字元之前,我們得先了解一下 ASCII 編碼。

ASCII 是一種字元編碼方式,它將字元和數字一一對應起來,用來在電腦中儲存字元。每一個字元都有自己的 ASCII 碼,比如說 a 就是 97,b 就是 98,0 就是 48,A 就是 65,等等。常見字元的 ASCII 編碼如下:

種類內容編碼
數字0~948~57
大寫字母A~Z65~90
小寫字母a~z97~122
空白32

ASCII 與字元

實際上字元在記憶體中其實是一個整數(ASCII 編碼),只是在輸出時會轉換成對應的字元。所以如果你想要知道字元的 ASCII 碼,可以把它強制轉型成 int 再輸出:

char a = 'a';
cout << (int)a; // 97

或者如果你需要的話,也可以把整數換成字元:

int a = 97;
cout << (char)a; // a

不過既然是整數,當然也可以進行運算:

char a = 'a';
char b = 'b';

cout << a + b << endl; // 195
cout << a + 1 << endl; // 98
cout << (char)(a + 1) << endl; // b

還可以這樣賦值:

char a = 97;
cout << a << endl; // a

字元與整數之間的轉換

前面我們提到,字元在記憶體中其實是一個代表 ASCII 碼的整數,所以當然可以被當作整數來用。不過要注意的是,字元和整數相加的時候,會被當作 ASCII 碼來運算,而不是「數字」。舉例來說:

char one = '1';
char two = '2';

cout << one + two << endl; // 99

那如果想要把字元轉成「數字」呢?這邊有一個小技巧,就是減去字元 '0',這樣就可以得到對應的數字了。這是因為 ASCII 碼中數字 '0''9' 是連續的,所以只要減去 '0' 就可以得到對應的數字,也就是他們的差值:

char one = '1';
char two = '2';

int one_num = one - '0';
cout << one_num << endl; // 1

int two_num = two - '0';
cout << two_num << endl; // 2

cout << one_num + two_num << endl; // 3
cout << two_num * 5 << endl; // 10

反過來,如果想要把數字轉成字元,只要加上 '0' 就可以了:

int a = 1;
int b = 2;

char a_char = a + '0';
cout << a_char << endl; // 1

char b_char = b + '0';
cout << b_char << endl; // 2

cout << a_char + b_char << endl; // 99

字元的比較

字元之間的比較和整數一樣,可以用 ==!=<><=>= 來比較。不過要注意的是,字元之間的比較是根據 ASCII 碼來比較的,舉例來說:

char a = 'a';
char b = 'b';
char c = 'c';

cout << (a < b) << endl; // true
cout << (a < c) << endl; // true
cout << (a > c) << endl; // false

和判斷字元有點相關的函式們

isalpha 這個函式是拿來判斷字元是否為字母,不是的話就回傳 0,否則就是一個非零整數。

char a;
cin >> a;
if (isalpha(a)) cout << "Yes";
else cout << "No";

isdigit 跟上面有點像,只是這次是判斷字元是不是數字,也是回傳 0 或非零整數。

char a;
cin >> a;
if (isdigit(a)) cout << "Yes";
else cout << "No";

isalnum 則是判斷字元是不是字母或數字,也是回傳 0 或非零整數。

char a;
cin >> a;
if (isalnum(a)) cout << "Yes";
else cout << "No";

islowerisupper 則是判斷字元是不是小寫或大寫字母,也是回傳 0 或非零整數。

char a;
cin >> a;
if (islower(a)) cout << "Yes";
else cout << "No";
char a;
cin >> a;
if (isupper(a)) cout << "Yes";
else cout << "No";
注意

再次強調,這邊有一點必須非常注意,isalphaisdigitisalnumislowerisupper 以上這些函式回傳的是 int,而不是 bool,而且可能的回傳值不只有 01,有些人可能會直覺的這麼寫:

if (isalpha(a) == 1) cout << "Yes";
else cout << "No";

但這樣寫是錯誤的,isalpha 的回傳值可能會因為不同字元、不同編譯器或者版本而有所不同,所以請絕對不要這樣寫!

來看看這份程式碼:

for (auto c = 'a'; c <= 'z'; c++) {
    cout << isalnum(c) << " ";
}

for (auto c = 'A'; c <= 'Z'; c++) {
    cout << isalnum(c) << " ";
}

for (auto c = '0'; c <= '9'; c++) {
    cout << isalnum(c) << " ";
}

以下是使用 GNU G++20 13.2 (64 bit, winlibs) 編譯器測試上面這段程式碼的結果:

2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 4 4 4 4 4 4 4 4 4 

可以看到 isalnum 回傳的值絕對不只有 01,所以請記得不要把 isalphaisdigitisalnumislowerisupper 拿來跟 1 比較!

下面這兩種寫法才是正確的:

if (isalpha(a)) cout << "Yes";
else cout << "No";
if (isalpha(a) != 0) cout << "Yes";
else cout << "No";

小測驗

如果把兩個字元相加,會得到什麼?