我們前面學(xué)習(xí)過輸出,printf函數(shù),標(biāo)準(zhǔn)庫提供了一次讀/寫一個字符的函數(shù),其中最簡單的是getchar和putchar,顧名思義,getchar為得到一個字符,putchar輸出一個字符。每次調(diào)用時,getchar函數(shù)從輸入流中讀取一個字符,并將其作為結(jié)果值返回,例如:
int c = getchar()
變量c中包含輸入流中的下一個字符,暫時是從鍵盤輸入。每次調(diào)用putchar()時將打印一個字符,例如
putchar(c)
將把整型變量c的內(nèi)容以字符的形式打印出來,通常是顯示在屏幕上
1.5.1 字符復(fù)制
下面這個程序為復(fù)制輸入,然后輸出
#include <stdio.h>
/* copy input to output; 1st version */
int main()
{
int c;
c = getchar();
while (c != EOF) {
putchar(c);
c = getchar();
}
return 0;
}
其中,關(guān)系運算符!=表示"不等于"。
char類型專門用于存儲字符型數(shù)據(jù),占用一個字節(jié),而任何整數(shù)型int也可以用于存儲字符型數(shù)據(jù),因為int一般占用四個字節(jié),不會溢出,因為某些潛在的重要原因,我們再次使用int類型。
在上例中,有一個特殊的字符常量EOF(end of file,文件結(jié)束),表示輸入流的結(jié)束。在輸入流結(jié)束或是文件流結(jié)束,getchar函數(shù)將會返回一個特殊值,與任何實際字符都不同,就是EOF。我們在聲明變量c的時候,必須讓它大到足以存放getchar函數(shù)返回的任何值。之所以不把c聲明成char,是因為它必須足夠大,除了能存儲任何可能的字符外還要能存儲文件結(jié)束符EOF。因此必須將c聲明稱int類型。EOF在頭文件<stdio.h>是個整形數(shù)-1,具體數(shù)值并不重要,只要它與任何char類型的值都不相同即可。這里使用符號常量,可以確保程序不需要依賴對應(yīng)的任何特定的數(shù)值。
可以將程序精煉如下:
#include <stdio.h>
/* copy input to output; 2nd version */
int main()
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}
在該程序中,while循環(huán)語句首先讀一個字符并將其賦值給c,然后測試是否為EOF,如果字符不是EOF,則執(zhí)行循環(huán)體,然后重復(fù)執(zhí)行while語句。當(dāng)?shù)竭_(dá)結(jié)尾位置(EOF),while循環(huán)語句終止執(zhí)行。
值得注意的是,在while ((c = getchar()) != EOF)中,c=getchar()兩端的小括號不可省略,因為關(guān)系運算符!=的優(yōu)先級比賦值運算符=高。
1.5.2 字符計數(shù)
下列程序用于對字符進(jìn)行計數(shù)
#include <stdio.h>
/* count characters in input; 1st version */
int main()
{
long nc;
nc = 0;
while (getchar() != EOF)
++nc;
printf("%ld\n", nc);
return 0;
}
其中循環(huán)體++nc引入了一個新的運算符++,其功能是執(zhí)行加1操作,叫做自增操作符,可以用nc = nc + 1代替它。與自增操作符對應(yīng)的為自減操作符--。++與--這兩個運算符既可以作為前綴操作符(++nc),也可以作為后綴操作符(nc++),關(guān)于這兩者的區(qū)別,我們以后介紹,當(dāng)然你也可以自行學(xué)習(xí)。
該字符計數(shù)程序使用long類型的變量存放計數(shù)值,而不是使用int,是因為long類型要比int大,至少會占用32位,在某些機器上,int占用16位,所以相當(dāng)小的輸入都可能使int類型的變量溢出。%ld指示printf函數(shù)對應(yīng)的參數(shù)是long類型。
使用double(雙精度浮點型)類型可以處理更大的數(shù)字。我們用double和for循環(huán)語句來展示編寫此循環(huán)的另一種方式:
#include <stdio.h>
/* count characters in input; 2nd version */
int main()
{
double nc;
for (nc = 0; getchar() != EOF; ++nc)
;
printf("%.0f\n", nc);
}
對于float與double類型,printf函數(shù)都使用%f進(jìn)行說明。%.0f表示不打印小數(shù)點和小數(shù)部分。
這段程序比較特殊的是我們的循環(huán)體是空的。我們的任務(wù)都在條件測試部分和增加步長部分完成了,但是for循環(huán)必須有一個循環(huán)體,所以我們寫一條空語句;。單獨的分號稱為空語句。
1.5.3 行計數(shù)
接下來的這個程序用于統(tǒng)計輸入中的行數(shù),判斷行數(shù)的方法就是看\n的個數(shù)
#include <stdio.h>
/* count lines in input */
int main()
{
int c, nl;
nl = 0;
while ((c = getchar()) != EOF)
if (c == '\n')
++nl;
printf("%d\n", nl);
}
在該程序中,while循環(huán)語句的循環(huán)體是一個if語句,它控制自增語句++nl。if語句先測試圓括號的條件,如果為真,就執(zhí)行后面的一條語句或是大括號括起來的一組語句,這里用縮進(jìn)來表示語句之間的控制關(guān)系。
雙等于號==是C語言中表示"關(guān)系"的運算符。記?。?code>=為賦值運算符,而==為是否相等的關(guān)系運算符,切記!
用單引號' \n'擴(kuò)住的字符表示一個整形數(shù),數(shù)值等于此字符在機器字符集中對應(yīng)的數(shù)值,我們成為字符常量。這是較小的整形數(shù)的另一種寫法。比如:'A'是一個字符常量,在ASCII字符集中其值為65。當(dāng)然,用'A'要比用65好,以為,'A'的意義更加清晰。
字符串常量中使用的轉(zhuǎn)義字符序列也是合法的字符常量,比如,'\n'代表換行符的值,在'ASCII'字符集中其值為10,應(yīng)對注意,'\n'是單個字符,在表達(dá)式中不過是一個整形數(shù)而已,而"\n"是一個僅包含一個字符的字符串常量。
1.5.4 單詞計數(shù)
我們介紹的這個程序用于統(tǒng)計行數(shù)、單詞數(shù)與字符數(shù)。這里單詞的定義為,不含空格、制表符或換行符的字符序列。
#include <stdio.h>
#define IN 1 /* inside a word */
#define OUT 0 /* outside a word */
/* count lines, words, and characters in input */
int main()
{
int c, nl, nw, nc, state;
state = OUT;
nl = nw = nc = 0;
while ((c = getchar()) != EOF) {
++nc;
if (c == '\n')
++nl;
if (c == ' ' || c == '\n' || c == '\t')
state = OUT;
else if (state == OUT) {
state = IN;
++nw;
}
}
printf("%d %d %d\n", nl, nw, nc);
return 0;
}
程序執(zhí)行時,每當(dāng)遇見單詞的第一個字符,它就作為一個新單詞加以統(tǒng)計。state變量記錄程序當(dāng)前是否正正位于一個單詞中,它的處置為OUT(不在單詞中),我們在這里使用了符號常量IN與OUT,而沒有使用1與0,這樣程序更易讀。
以下語句
nl = nw = nc = 0;
這種賦值方式為聯(lián)合賦值方式,由于賦值運算符=的結(jié)合性為右結(jié)合,所以等價于:
n1 = (nw = (nc = 0));
運算符||代表OR(邏輯或),所以以下語句
if (c == ' ' || c== '\n' || c == '\t')
的意義為"如果c是空格,或換行符,或制表符",與之對應(yīng)的,運算符&&代表AND(邏輯與),它比||高一個優(yōu)先級。由&&或||連接的表達(dá)式由左至右求值,并在求值過程中只要能判斷出最終結(jié)果為真或假,就立即終止。這種特性稱為短路。比如:
a = 1,b = 2;
if(a == 1 || b == 1){
printf("a為1或b為1")
}
||只要有一個真,整個表達(dá)式的值就為真,所以比較完a==1,即可求出表達(dá)式的值為真,所以b==1就不會比較。
這段程序中還包括一個else部分,它指定if語句中的條件部分為假時所要執(zhí)行的動作,一般形式為:
if(表達(dá)式)
語句1;
else
語句2;
if后的條件為真執(zhí)行語句1,為假執(zhí)行語句2,語句1和語句2都可以是單條語句或是大括號括起來的多條語句。