第一章為程序設(shè)計基礎(chǔ),本文為1.8.1 字符常量。
>>>1.字符常量的引用
字符常量是使用一對單引號“''”包圍起來的,比如,'O','編譯器知道這個符號指的是字母O的ASCII值,即79。同樣可以用' '指出空格,或用'9'指出數(shù)字9。常量'9'指的是一個字符,不應(yīng)該與整數(shù)值9混淆。除非程序員能記住ASCII碼表,否則任何人看到79都不會聯(lián)想到字母O,而字符常量'O' 則可以直接傳遞它的意義。
在C語言中,字符能象整數(shù)一樣計算,不需要特別的轉(zhuǎn)換?;诖耍瓤梢越o一個字符加上一個整數(shù),比如,字符c與整數(shù)n相加,即c+n表示c后面的第n個字符。也可以從一個字符減去一個整數(shù),比如,表達式c-n表示c前面的第n個字符。還可以從一個字符減去另一個字符,比如,c1和c2都是字符,那么c1-c2表示兩個字符的距離。
更進一步地,還可以比較兩個字符,如果在ASCII表中,c1在c2前面,那么c1
if( ch >= '0' && ch <= '9' )??? { … }
這樣一來就將數(shù)字字符與ASCII碼表中的其它字符區(qū)分開了。雖然標(biāo)準(zhǔn)C接口ctype.h提供了相應(yīng)的函數(shù),但如果你從頭到尾實現(xiàn)它們,則有助于進一步深入了解它們的操作。如果ch是大寫字母,返回它對應(yīng)的小寫字母,否則返回ch本身,詳見程序清單 1.35。
程序清單1.35 tolower()函數(shù)范例程序
1 char tolower(char ch)
2 {
3 if( ch >= 'A' && ch <= 'Z' ){????????????????????????????? //標(biāo)識大寫字母
4 return (ch + ('a' - 'A'));
5 }else{
6 return (ch);
7 }
8 }
>>>2. 字符的輸入輸出
雖然轉(zhuǎn)換符%c允許scanf()函數(shù)和printf()函數(shù)對一個單獨的字符進行讀寫操作。比如:
char ch;
scanf("%c", &ch);
printf("%c", ch);
但在讀入字符前,scanf()函數(shù)不會跳過空格符,即會將空格作為字符讀入變量ch。為了解決這個問題,則必須在%c的前面加一個空格:
scanf(" %c", &ch);
雖然scanf()函數(shù)不會跳過空格符,卻很容易檢測到讀入的字符是否為換行符' '。比如:
while(ch != ' '){
scanf("%c", &ch);
}
當(dāng)然也可以調(diào)用getchar()和putchar()讀寫一個單獨的字符,它們是在stdio.h中定義的宏,分別用于從鍵盤讀取數(shù)據(jù)和將字符打印到屏幕上。雖然宏和函數(shù)在技術(shù)上存在一些區(qū)別,但它們的用法是一樣的。比如:
int getchar(void);//輸入一個字符
int putchar(int ch);//輸出一個字符
getchar()函數(shù)不帶任何參數(shù),它從輸入隊列中返回一個字符。比如,下面的語句讀取一個字符輸入,并將該字符的值賦給變量ch:
ch = getchar();
該語句與下面的語句等效:
scanf("%c", &ch);
putchar()函數(shù)打印它的參數(shù),比如,下面的語句將之前賦給ch的值作為字符打印出來:
putchar(ch);
該語句與下面的語句效果相同:
printf("%c", ch);
由于這些函數(shù)只處理字符,因此它們比scanf()和printf()函數(shù)更快,這兩個函數(shù)通常定義在stdio.h中,實際上它們是預(yù)處理宏,不是真正的函數(shù)。雖然這些宏看起來很簡單,但有時出了問題,卻找不出原因。比如:
char ch1, ch2;
ch1 = getchar();
ch2 = getchar();
printf("%d %d ", ch1, ch2);
此時,如果輸入字符'a',而打印結(jié)果卻是“97,10”。因為從鍵盤輸入一個字符后,就打印出了結(jié)果,還沒有輸入第二個字符程序就結(jié)束了。由于鍵盤輸入一次結(jié)束后,會將數(shù)據(jù)存儲在一個被稱為緩沖區(qū)的臨時存儲區(qū),按下Enter鍵后程序才可使用用戶輸入的字符,因此scanf()和getchar()也是從輸入流緩沖區(qū)中取值的,而人們常常會產(chǎn)生這樣的錯覺,誤以為它們是從鍵盤緩沖區(qū)取值的。實際上,數(shù)據(jù)是通過cin函數(shù)直接從輸入流緩沖區(qū)中取走的,所以,當(dāng)緩沖區(qū)中有殘留數(shù)據(jù)時,cin函數(shù)會直接讀取這些殘留數(shù)據(jù)而不會請求鍵盤輸入。
這里的10恰好是Enter鍵輸入的換行符' ',當(dāng)讀取數(shù)據(jù)遇到換行符' '結(jié)束時,換行符會一起讀入輸入流緩沖區(qū),所以第一次接受輸入時,取走字符后會留下字符' ',于是第二次直接從緩沖區(qū)中將 取走。
為何要有緩沖區(qū)呢?首先,將若干字符作為一個塊進行傳輸比逐個發(fā)送這些字符節(jié)約時間。其次,如果用戶打錯字符,可以直接通過鍵盤修正錯誤。當(dāng)最后按下Enter鍵時,傳輸?shù)氖钦_的輸入。雖然輸入緩沖區(qū)的好處很多,但在某些交互式程序中也需要無緩沖區(qū)輸入。比如,在游戲中,如果希望按下一個鍵就執(zhí)行相應(yīng)的命令,因此緩沖輸入和無緩沖輸入各有各的用武之地,但本書假設(shè)所有的輸入都是緩沖輸入。
緩沖分為兩類:完全緩沖I/O和行緩沖I/O,完全緩沖輸入指的是當(dāng)緩沖區(qū)被填滿時才刷新緩沖區(qū),內(nèi)容被發(fā)送到目的地,通常出現(xiàn)在文件輸入中。緩沖區(qū)的大小取決于系統(tǒng),常見的大小為512字節(jié)和4096字節(jié)。行緩沖區(qū)I/O指的是在出現(xiàn)換行符時刷新緩沖區(qū),鍵盤輸入通常是行緩沖區(qū)輸入,所以在按下Enter鍵后才刷新緩沖區(qū)。
getchar()讀取每個字符,包括空格、制表符和換行符;而scanf()在讀取數(shù)字時,則會跳過空格、制表符和換行符。雖然這兩個函數(shù)都很好用,但不能混合使用。
雖然putchar()的參數(shù)ch定義為int類型,但實質(zhì)上它接收的是一個char類型字符,因為在putchar()內(nèi)部,系統(tǒng)會將ch強制轉(zhuǎn)換為char類型后再使用。如果字符輸出成功,則putchar()返回輸出的字符((char)ch),而不是輸入的參數(shù)ch;如果不成功,則返回預(yù)定義的常量EOF(end of file,文件結(jié)束),EOF是一個整數(shù)。
getchar()沒有輸入?yún)?shù),其返回值為int型,而不是char型。這里需要區(qū)分文件中的有效數(shù)據(jù)和輸入結(jié)束符,當(dāng)有字符可讀時,getchar()不會返回文件結(jié)束符EOF,所以
ch = getchar() != EOF //相當(dāng)于ch = (getchar() != EOF)
取值為true,變量ch被賦值為1。
當(dāng)程序沒有輸入時,則getchar()返回文件結(jié)束符EOF,即表達式取值為false,此時變量ch被賦值為0,程序結(jié)束運行。如果將getchar()函數(shù)的返回值定義為int型,則既能存儲任何可能的字符,也能存儲文件結(jié)束符EOF,將輸入復(fù)制到輸出的例程序詳見程序清單1.36。
程序清單1.36將輸入復(fù)制到輸出范例程序
1 #include
2 int main(int argc, char *argv[])
3 {
4 int ch;
5
6 while((ch = getchar()) != EOF){
7 putchar(ch);
8 }
9 return 0;
10 }
當(dāng)然,也可以用getchar()的另一種慣用法替代程序清單1.36(6):
while((ch = getchar()) != ' ')
即將讀入的一個字符與換行符比較,如果測試結(jié)果為true,則執(zhí)行循環(huán)體,接著重復(fù)測試循環(huán)條件,再讀入一個新的字符,同時getchar()用于搜索字符和跳過字符等效。比如:
while((ch = getchar()) == ' ')
當(dāng)循環(huán)終止時,變量ch將包含getchar()遇到的第一個非空字符。
do-while循環(huán)遠比for和while循環(huán)用得小,因為它至少需要執(zhí)行循環(huán)體一次,且在代碼的最后而不是開始執(zhí)行條件循環(huán)測試。邏輯條件應(yīng)該出現(xiàn)在它們所“保護”的代碼之前,這也是if、while和for的工作方式。通常閱讀代碼的習(xí)慣是從前向后,當(dāng)使用do/while循環(huán)時,需要對這段代碼讀兩次。同時,這種方式在很多情況下是不正確的,比如:
? do{
? ch = getchar();
? putchar(ch);
? }while(ch != EOF);
由于測試被放在對putchar()的調(diào)用之后,因此該代碼無端地多寫了一個字符。只有在某個循環(huán)體必須至少執(zhí)行一次的情況下,使用do-while循環(huán)才是正確的。
另一個讓人迷惑的是,do/while循環(huán)中的contiune語句:
do{
continue;
}while(false);
它會永遠循環(huán)下去還是只執(zhí)行一次?雖然它只會循環(huán)一次,但大多數(shù)人都會想一想。C++的開創(chuàng)者Bjarne Stroustrup是這樣說的,“do語句是錯誤和困惑的來源,我傾向于將條件放在前面我能看到的地方,避免使用do語句?!?/span>
-
C語言編程
+關(guān)注
關(guān)注
6文章
90瀏覽量
21103
原文標(biāo)題:周立功:字符能像整數(shù)一樣計算
文章出處:【微信號:ZLG_zhiyuan,微信公眾號:ZLG致遠電子】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論