char類型用于存儲字符(如,字母或標點符號),但是從技術層面看,char是整數類型。因為char類型實際上存儲的是整數而不是字符。計算機使用數字編碼來處理字符,即用特定的整數表示特定的字符。美國最常用的編碼是ASCII編碼,本書也使用此編碼。例如,在ASCII碼中,整數65代表大寫字母A。因此,存儲字母A實際上存儲的是整數65。標準ASCII碼的范圍是0~127,只需7位二進制數即可表示。通常,char類型被定義為8位的存儲單元,因此容納標準ASCII碼綽綽有余。一般而言,C語言會保證char類型足夠大,以存儲系統(實現C語言的系統)的基本字符集。許多字符集都超過了127,甚至多于255。例如,日本漢字(kanji)字符集。商用的統一碼(Unicode)創建了一個能表示世界范圍內多種字符集的系統,目前包含的字符已超過110000個。國際標準化組織(ISO)和國際電工技術委員會(IEC)為字符集開發了ISO/IEC 10646標準。統一碼標準也與ISO/IEC 10646標準兼容。
C語言把1字節定義為char類型占用的位(bit)數,因此無論是16位還是32位系統,都可以使用char類型。
1.聲明char類型變量
char類型變量的聲明方式與其他類型變量的聲明方式相同。下面是一些例子:
char response
char itable
以上聲明創建了3個char類型的變量:response、itable和latan。
2.字符常量和初始化
如果要把一個字符常量初始化為字母A,不必背下ASCII碼,用計算機語言很容易做到。通過以下初始化把字母A賦給grade即可:
char grade = 'A';
在C語言中,用單引號括起來的單個字符被稱為字符常量(characterconstant)。編譯器一發現'A',就會將其轉換成相應的代碼值。單引號必不可少。下面還有一些其他的例子:
char broiled; /* declare a char variable */
broiled = 'T'; /* OK */
broiled = T; /* NO! Thinks T is a variable */
broiled = "T"; /* NO! Thinks "T" is a string */
如上所示,如果省略單引號,編譯器認為T是一個變量名;如果把T用雙引號括起來,編譯器則認為"T"是一個字符串。字符串的內容將在第4章中介紹。
實際上,字符是以數值形式存儲的,所以也可使用數字代碼值來賦值:
在本例中,雖然65是int類型,但是它在char類型能表示的范圍內,所以將其賦值給grade沒問題。由于65是字母A對應的ASCII碼,因此本例是把A賦給grade。注意,能這樣做的前提是系統使用ASCII碼。其實,用'A'代替65才是較為妥當的做法,這樣在任何系統中都不會出問題。因此,最好使用字符常量,而不是數字代碼值。奇怪的是,C語言將字符常量視為int類型而非char類型。例如,在int為32位、char為8位的ASCII系統中,有下面的代碼:
char grade = 'B';
本來'B'對應的數值66存儲在32位的存儲單元中,現在卻可以存儲在8位的存儲單元中(grade)。利用字符常量的這種特性,可以定義一個字符常量'FATE',即把4個獨立的8位ASCII碼存儲在一個32位存儲單元中。如果把這樣的字符常量賦給char類型變量grade,只有最后8位有效。因此,grade的值是'E'。
3.非打印字符
單引號只適用于字符、數字和標點符號,瀏覽ASCII表會發現,有些ASCII字符打印不出來。例如,一些代表行為的字符(如,退格、換行、終端響鈴或蜂鳴)。C語言提供了3種方法表示這些字符。
第1種方法前面介紹過—使用ASCII碼。例如,蜂鳴字符的ASCII值是7,因此可以這樣寫:
char beep = 7
第2種方法是,使用特殊的符號序列表示一些特殊的字符。這些符號序列叫作轉義序列(escape sequence)。表3.2列出了轉義序列及其含義。把轉義序列賦給字符變量時,必須用單引號把轉義序列括起來。例如,假設有下面一行代碼:
char nerf = 'n'
稍后打印變量nerf的效果是,在打印機或屏幕上另起一行。

Table 3.2 Escape Sequences
現在,我們來仔細分析一下轉義序列。使用C90新增的警報字符(a)是否能產生聽到或看到的警報,取決于計算機的硬件,蜂鳴是最常見的警報(在一些系統中,警報字符不起作用)。C標準規定警報字符不得改變活躍位置。標準中的活躍位置(active-position)指的是顯示設備(屏幕、電傳打字機、打印機等)中下一個字符將出現的位置。簡而言之,平時常說的屏幕光標位置就是活躍位置。在程序中把警報字符輸出在屏幕上的效果是,發出一聲蜂鳴,但不會移動屏幕光標。接下來的轉義字符b、f、n、r、t和v是常用的輸出設備控制字符。了解它們最好的方式是查看它們對活躍位置的影響。換頁符(f)把活躍位置移至下一頁的開始處;換行符(n)把活躍位置移至下一行的開始處;回車符(r)把活躍位置移動到當前行的開始處;水平制表符(t)將活躍位置移至下一個水平制表點(通常是第1個、第9個、第17個、第25個等字符位置);垂直制表符(v)把活躍位置移至下一個垂直制表點。這些轉義序列字符不一定在所有的顯示設備上都起作用。例如,換頁符和垂直制表符在PC屏幕上會生成奇怪的符號,光標并不會移動。只有將其輸出到打印機上時才會產生前面描述的效果。
接下來的3個轉義序列(\、'、")用于打印、'、"字符(由于這些字符用于定義字符常量,是printf()函數的一部分,若直接使用它們會造成混亂)。如果打印下面一行內容:
Gramps sez, "a is a backslash."
應這樣編寫代碼:
printf("Gramps sez, "a \ is a backslash."n");
: Gramps sez, "a is a backslash."
表3.2中的最后兩個轉義序列(oo和\xhh)是ASCII碼的特殊表示。如果要用八進制ASCII碼表示一個字符,可以在編碼值前面加一個反斜杠()并用單引號括起來。例如,如果編譯器不識別警報字符(a),可以使用ASCII碼來代替:
beep = '07'
可以省略前面的0,'7'甚至'7'都可以。即使沒有前綴0,編譯器在處理這種寫法時,仍會解釋為八進制。
從C90開始,不僅可以用十進制、八進制形式表示字符常量,C語言還提供了第3種選擇—用十六進制形式表示字符常量,即反斜杠后面跟一個x或X,再加上1~3位十六進制數字。例如,Ctrl+P字符的ASCII十六進制碼是10(相當于十進制的16),可表示為'\x10'或'\x010'。圖3.5列出了一些整數類型的不同進制形式。

Figure 3.5 Writing constants with the =int= family.
使用ASCII碼時,注意數字和數字字符的區別。例如,字符4對應的ASCII碼是52。'4'表示字符4,而不是數值4。關于轉義序列,讀者可能有下面3個問題。
- 上面最后一個例子(printf("Gramps sez, "a \ is abackslash."n"),為何沒有用單引號把轉義序列括起來?無論是普通字符還是轉義序列,只要是雙引號括起來的字符集合,就無需用單引號括起來。雙引號中的字符集合叫作字符串(詳見第4章)。注意,該例中的其他字符(G、r、a、m、p、s等)都沒有用單引號括起來。與此類似,printf("Hello!07n");將打印Hello!并發出一聲蜂鳴,而printf("Hello!7n");則打印Hello!7。不是轉義序列中的數字將作為普通字符被打印出來。
- 何時使用ASCII碼?何時使用轉義序列?如果要在轉義序列(假設使用'f')和ASCII碼('14')之間選擇,請選擇前者(即'f')。這樣的寫法不僅更好記,而且可移植性更高。'f'在不使用ASCII碼的系統中,仍然有效。
- 如果要使用ASCII碼,為何要寫成'32'而不是032?首先,'32'能更清晰地表達程序員使用字符編碼的意圖。其次,類似32這樣的轉義序列可以嵌入C的字符串中,如printf("Hello!07n");中就嵌入了07。
printf("Hello!62n");
: Hello!2
4.打印字符
printf()函數用%c指明待打印的字符。前面介紹過,一個字符變量實際上被存儲為1字節的整數值。因此,如果用%d轉換說明打印char類型變量的值,打印的是一個整數。而%c轉換說明告訴printf()打印該整數值對應的字符。程序清單3.5演示了打印char類型變量的兩種方式。
/* charcode.c-displays code number for a character */
#include <stdio.h>
int main(void)
{
char ch;
printf("Please enter a character.n");
scanf("%c", &ch); /* user inputs character */
printf("The code for %c is %d.n", ch, ch);
return 0;
}
# 運行該程序后,輸出示例如下:
Here is a sample run:
Please enter a character.
C
The code for C is 67.
運行該程序時,在輸入字母后不要忘記按下Enter或Return鍵。隨后,scanf()函數會讀取用戶輸入的字符,&符號表示把輸入的字符賦給變量ch。接著,printf()函數打印ch的值兩次,第1次打印一個字符(對應代碼中的%c),第2次打印一個十進制整數值(對應代碼中的%d)。注意,printf()函數中的轉換說明決定了數據的顯示方式,而不是數據的存儲方式(見圖3.6)。

Figure 3.6 Data display versus data storage.
5.有符號還是無符號
有些C編譯器把char實現為有符號類型,這意味著char可表示的范圍是-128~127。
而有些C編譯器把char實現為無符號類型,那么char可表示的范圍是0~255。請查閱相應的編譯器手冊,確定正在使用的編譯器如何實現char類型。或者,可以查閱limits.h頭文件。下一章將詳細介紹頭文件的內容。根據C90標準,C語言允許在關鍵字char前面使用signed或unsigned。這樣,無論編譯器默認char是什么類型,signed char表示有符號類型,而unsigned char表示無符號類型。這在用char類型處理小整數時很有用。如果只用char處理字符,那么char前面無需使用任何修飾符。