C程序設(shè)計(jì)語(yǔ)言(第2版·新版)文字版_第1頁(yè)
C程序設(shè)計(jì)語(yǔ)言(第2版·新版)文字版_第2頁(yè)
C程序設(shè)計(jì)語(yǔ)言(第2版·新版)文字版_第3頁(yè)
C程序設(shè)計(jì)語(yǔ)言(第2版·新版)文字版_第4頁(yè)
已閱讀5頁(yè),還剩209頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第1早導(dǎo)白在本書(shū)的開(kāi)篇,我們首先概要地介紹C語(yǔ)言,主要是通過(guò)實(shí)際的程序用入C語(yǔ)言的基本元素,至于其中的具體細(xì)節(jié)、規(guī)則以及ー些例外情況,在此暫時(shí)不多做討論。因此,本章不準(zhǔn)備完整、詳細(xì)地討論C語(yǔ)言中的ー些技術(shù)(當(dāng)然,這里所舉的所有例子都是正確的)。我們是希望讀者能盡快地編寫(xiě)出有用的程序,為此,本章將重點(diǎn)介紹ー些基本概念,比如變量與常量、算術(shù)運(yùn)算、控制流、函數(shù)、基本輸入/輸出等。而對(duì)于編寫(xiě)較大型程序所涉及到的ー些重要特性,比如指針、結(jié)構(gòu)、C語(yǔ)言中十分豐富的運(yùn)算符集合、部分控制流語(yǔ)句以及標(biāo)準(zhǔn)庫(kù)等,本章將暫不做討論。這種講解方式也有缺點(diǎn)。應(yīng)當(dāng)提請(qǐng)注意的是,在本章的內(nèi)容中無(wú)法找到任何特定語(yǔ)言特性的完整說(shuō)明,并且,由于比較簡(jiǎn)略,可能會(huì)使讀者產(chǎn)生一些誤解;再者,由于所舉的例子并沒(méi)有用到c語(yǔ)言的所有強(qiáng)大功能,因此,這些例子也許并不簡(jiǎn)潔、精煉。雖然我們已經(jīng)盡力將這些問(wèn)題的影響降到最低,但問(wèn)題肯定還是存在。另ー個(gè)不足之處在于,本章所講的某些內(nèi)容在后續(xù)相關(guān)章節(jié)還必須再次講述。我們希望這種重復(fù)給讀者帶來(lái)的幫助效果遠(yuǎn)遠(yuǎn)超過(guò)它的負(fù)面影響。無(wú)論是利還是弊,ー個(gè)經(jīng)驗(yàn)豐富的程序員應(yīng)該可以從本章介紹的內(nèi)容中推知他們自己進(jìn)行程序設(shè)計(jì)所需要的一些基本元素。初學(xué)者應(yīng)編寫(xiě)ー些類似的小程序作為本章內(nèi)容的補(bǔ)充練習(xí)。無(wú)論是經(jīng)驗(yàn)豐富的程序員還是初學(xué)者,都可以把本章作為后續(xù)各章詳細(xì)講解的內(nèi)容的框架。入門(mén)學(xué)習(xí)ー門(mén)新程序設(shè)計(jì)語(yǔ)言的惟一途徑就是使用它編寫(xiě)程序。對(duì)于所有語(yǔ)言的初學(xué)者來(lái)說(shuō),編寫(xiě)的笫ー個(gè)程序幾乎都是相同的,即:請(qǐng)打印出下列內(nèi)容hello,world盡管這個(gè)練習(xí)很簡(jiǎn)單,但對(duì)于初學(xué)語(yǔ)言的人來(lái)說(shuō),它仍然可能成為一大障礙,因?yàn)橐獙?shí)現(xiàn)這個(gè)目的,我們首先必須編寫(xiě)程序文本,然后成功地運(yùn)行編譯,并加載、運(yùn)行,最后輸出到某個(gè)地方。掌握了這些操作細(xì)節(jié)以后,其它事情就比較容易了。在C語(yǔ)言中,我們可以用下列程序打印出‘'hello,world":^include<stdio.h>main()(printflhello,worid\n");}如何運(yùn)行這個(gè)程序取決于所使用的系統(tǒng)。這里舉一個(gè)籽殊的例子。在UNIX操作系統(tǒng)中,首先必須在某個(gè)文件中建立這個(gè)源程序,并以“.c”作為文件的擴(kuò)展名,例如hello.c,然后再通過(guò)下列命令進(jìn)行編譯,cchello.c如果源程序沒(méi)有什么錯(cuò)誤(例如漏掉字符或拼錯(cuò)字符),編譯過(guò)程將順利進(jìn)行,井生成一個(gè)可執(zhí)行文件a.out。然后,我們輸入:a.out即可運(yùn)行a.out,打印出下列信息:hello,world在其它操作系統(tǒng)中,編譯、加載、運(yùn)行等規(guī)則會(huì)有所不同。tinclude<stdio.h> 包含標(biāo)準(zhǔn)庫(kù)的信息mainO 定義名為main的函數(shù),它不接受參數(shù)值( main函數(shù)的語(yǔ)句都被括在花括號(hào)中printf(*hello,world\n*); main函數(shù)調(diào)用庫(kù)函數(shù)printf以顯示字符序列:)\n代表?yè)Q行符 第一個(gè)C語(yǔ)言程序 下面對(duì)程序本身做些說(shuō)明。ー個(gè)C語(yǔ)言程序,無(wú)論其大小如何,都是由函數(shù)和變量組成的。函數(shù)中包含一些語(yǔ)句,以指定所要執(zhí)行的計(jì)算操作;變量則用于存儲(chǔ)計(jì)算過(guò)程中使用的值。c語(yǔ)言中的函數(shù)類似于Fortran語(yǔ)言中的子程序和函數(shù),與Pascal語(yǔ)言中的過(guò)程和函數(shù)也很類似。在本例中,函數(shù)的名字為main。通常情況下,函數(shù)的命名沒(méi)有限制,但main是ー個(gè)特殊的函數(shù)名ーー每個(gè)程序都從main函數(shù)的起點(diǎn)開(kāi)始執(zhí)行,這意味著每個(gè)程序都必須在某個(gè)位置包含一個(gè)main函數(shù)。main函數(shù)通常會(huì)調(diào)用其它函數(shù)來(lái)幫助完成某些工作,被調(diào)用的函數(shù)可以是程序設(shè)計(jì)人員自己編寫(xiě)的,也可以來(lái)自于函數(shù)庫(kù)。上述程序段中的第一行語(yǔ)句^include<stdio.h>用于告訴編譯器在本程序中包含標(biāo)準(zhǔn)輸入/輸出庫(kù)的信息。許多c語(yǔ)言源程序的開(kāi)始處都包含這一行語(yǔ)句。我們將在第7章和附錄B中對(duì)標(biāo)準(zhǔn)庫(kù)進(jìn)行詳細(xì)介紹。函數(shù)之間進(jìn)行數(shù)據(jù)交換的ー種方法是調(diào)用函數(shù)向被調(diào)用函數(shù)提供ー個(gè)值(稱為參數(shù))列表。函數(shù)名后面的ー對(duì)圓括號(hào)將參數(shù)列表括起來(lái)。在本例中,main函數(shù)不需要任何參數(shù),因此用空參數(shù)表〇表示。函數(shù)中的語(yǔ)句用ー對(duì)花括號(hào)〇括起來(lái)。本例中的main函數(shù)僅包含下面一條語(yǔ)句:printf(*hello,world\n*);調(diào)用函數(shù)時(shí),只需要使用函數(shù)名加上用圓括號(hào)括起來(lái)的參數(shù)表即可。上面這條語(yǔ)句將"hello,world\n"?作為參數(shù)調(diào)用printf函數(shù)。printf是ー個(gè)用于打印輸出的庫(kù)函數(shù),在此處,它打印雙引號(hào)中間的字符串。用雙引號(hào)括起來(lái)的字符序列稱為字符串或字符串常量,如"hell。,world'n"就是ー個(gè)字符串。目前我們僅使用字符串作為printf及其它函數(shù)的參數(shù)。在C語(yǔ)言中,字符序列、卩表示換行符,在打印中遇到它時(shí),輸出打印將換行,從下一行的左端行首開(kāi)始。如果去掉字符串中的'n(這是個(gè)值得一做的練習(xí)),即使輸出打印完成后也不會(huì)換行。在printf函數(shù)的參數(shù)中,只能用'n表示換行符。如果用程序的換行代替、卩,例如:printf("hello,world");C編譯器將會(huì)產(chǎn)生一條錯(cuò)誤信息。printf函數(shù)永遠(yuǎn)不會(huì)自動(dòng)換行,這樣我們可以多次調(diào)用該函數(shù)以分階段得到ー個(gè)長(zhǎng)的輸出行。上面給出的第一個(gè)程序也可以改寫(xiě)成下列形式,ttinclude<stdio.h>main(){printf("hello,");printf("world");printf("'n");}這段程序與前面的程序的輸出相同。請(qǐng)注意,'n只代表ー個(gè)字符。類似『'n的轉(zhuǎn)義字符序列為表示無(wú)法輸入的字符或不可見(jiàn)字符提供了一種通用的可擴(kuò)充的機(jī)制。除此之外,C語(yǔ)言提供的轉(zhuǎn)義字符序列還包括:\t表示制表符;\b表示回退符:'”表示雙引號(hào);い表示反斜杠符本身。2.3節(jié)將給出轉(zhuǎn)義字符序列的完整列表。練習(xí)1T在你自己的系統(tǒng)中運(yùn)行“hello,world”程序。再有意去掉程序中的部分內(nèi)容,看看會(huì)得到什么出錯(cuò)信息。練習(xí)1-2做個(gè)實(shí)驗(yàn),當(dāng)printf函數(shù)的參數(shù)字符串中包含'c(其中c是上面的轉(zhuǎn)義字符序列中未曾列出的某ー個(gè)字符)時(shí),觀察一下會(huì)出現(xiàn)什么情況。1.2.變量與算術(shù)表達(dá)式我們來(lái)看ドー個(gè)程序,使用公式。C=(5/9)(0F-32)打印ド列華氏溫度與攝氏溫度對(duì)照表:1-1720-640460158026100371204814060160711808220093220104240115260126280137300148此程序中仍然只包括一個(gè)名為main的函數(shù)定義。它比前面打印“hello,world”的程序長(zhǎng)ー些,但并不復(fù)雜。這個(gè)程序中引入了一些新的概念,包括注釋、聲明、變量、算術(shù)表達(dá)式、循環(huán)以及格式化輸出。該程序如下所示:^include<stdio.h>/?當(dāng)fahr二〇,2Of...,300時(shí),分另lj打印華氏溫度與攝氏溫度對(duì)照表?/main()(intfahr,Celsius;intlower,upper,step;lower=0; /?溫度表的下限?//*upper=300 溫度表的上限?//?步長(zhǎng)step=20; */fahr=lower;while(fahr<=upper){Celsius=5*(fahr-32)/9;printf("%d\t%d\n”,fahr,Celsius);fahr=fahr+step;其中的兩行:/?當(dāng)fahr=O,20 300時(shí),分另lj打印華氏溫度與攝氏溫度對(duì)照表?/稱為注釋,此處,它簡(jiǎn)單地解釋,該程序是做什么用的。包含在/?與?/之間的字符序列將被編譯器忽略。注釋可以自由地運(yùn)用在程序中,使得程序更易于理解。程序中允許出現(xiàn)空格、制表符或換行符之處,都可以使用注釋。在C語(yǔ)言中,所有變量都必須先聲明后使用。聲明通常放在函數(shù)起始處,在任何可執(zhí)行語(yǔ)句之前。聲明用于說(shuō)明變量的屬性,它由一個(gè)類型名和一個(gè)變量表組成,例如,intfahr,Celsius;intlower,upper,step其中,類型int表示其后所列變量為整數(shù),與之相對(duì)應(yīng)的,float表示所列變量為浮點(diǎn)數(shù)(即,可以帶有小數(shù)部分的數(shù))。int與float類型的取值范圍取決于具體的機(jī)器。對(duì)于int類型,通常為!6位,其取值范圍在ー32768?32767之間,也冇用32位表示的int類型。float類型通常是32位,它至少有6位有效數(shù)字,取值范圍一般在10"?10"之間。除int與float類型之外,C語(yǔ)高還提供了其它ー些基本數(shù)據(jù)類型,例如,char變符 個(gè)字節(jié)short 短整型long 長(zhǎng)整型double 雙精度浮點(diǎn)型這些數(shù)據(jù)類型對(duì)象的大小也取決于具體的機(jī)器。另外,還存在這些基本數(shù)據(jù)類型的數(shù)組、結(jié)構(gòu)、聯(lián)合,指向這些類型的指針以及返回這些類型值的函教。我們將在后續(xù)相應(yīng)的章節(jié)中分別介紹。在上面的溫度轉(zhuǎn)換程序中,最開(kāi)始執(zhí)行的計(jì)算是ド列4個(gè)賦值語(yǔ)句:lower=0;upper=300;step=20;fahr=lower;它們?yōu)樽兞吭O(shè)置初值。各條語(yǔ)句均以分號(hào)結(jié)束。溫度轉(zhuǎn)換表中的各行計(jì)算方式相同,因此可以用循環(huán)語(yǔ)句重復(fù)輸出各行。這是while循環(huán)語(yǔ)句的用途.while(fahr<=upper){while循環(huán)語(yǔ)句的執(zhí)行方式是這樣的:首先測(cè)試圓括號(hào)中的條件;如果條件為真(fahr<=upper),則執(zhí)行循環(huán)體(括在花括號(hào)中的3條語(yǔ)句);然后再重新測(cè)試圓括號(hào)中的條件,如果為真,則再次執(zhí)行循環(huán)體;當(dāng)圓括號(hào)中的條件測(cè)試結(jié)果為假(fahr>upper)時(shí),循環(huán)結(jié)束,并繼續(xù)執(zhí)行跟在while循環(huán)語(yǔ)句之后的下一條語(yǔ)句。在本程序中,循環(huán)語(yǔ)句后沒(méi)有其它語(yǔ)句,因此整個(gè)程序的執(zhí)行終止。while語(yǔ)句的循環(huán)體可以是用花括號(hào)括起來(lái)的一條或多條語(yǔ)句(如上面的溫度轉(zhuǎn)換程序),也可以是不用花括號(hào)包括的單條語(yǔ)句,例如,while(i<j)i=2*i;在這兩種情況下,我們總是把由while控制的語(yǔ)句縮進(jìn)ー個(gè)制表位,這樣就可以很容易地看出循環(huán)語(yǔ)句中包含哪些語(yǔ)句。這種縮進(jìn)方式突出了程序的邏輯結(jié)構(gòu)。盡管C編譯器并不關(guān)心程序的外觀形式,但正確的縮進(jìn)以及保留適當(dāng)空格的程序設(shè)計(jì)風(fēng)格對(duì)程序的易讀性非常重要。我們建議每行只書(shū)寫(xiě)一條語(yǔ)句,并在運(yùn)算符兩邊各加上一個(gè)空格字符,這樣可以使得運(yùn)算的結(jié)合關(guān)系更清楚明了。相比而言,花括號(hào)的位置就不那么重要了。我們從比較流行的ー些風(fēng)格中選擇了一種,讀者可以選擇適合自己的ー種風(fēng)格,并養(yǎng)成一直使用這種風(fēng)格的好習(xí)慣。在該程序中,絕大部分工作都是在循環(huán)體中完成的。循環(huán)體中的賦值語(yǔ)句Celsius=5*(fahr-32)/9:用于計(jì)算與指定華氏溫度相對(duì)應(yīng)的攝氏溫度值,并將結(jié)果賦值給變量celsius。在該語(yǔ)句中,之所以把表達(dá)式寫(xiě)成先乘5然后再除以9而不是宜接寫(xiě)成5/9,其原因是在C語(yǔ)言及許多其它語(yǔ)言中,整數(shù)除法操作將執(zhí)行舍位,結(jié)果中的任何小數(shù)部分都會(huì)被舍棄。由于5和9都是整數(shù),5/9相除后經(jīng)截取所得的結(jié)果為〇,因此這樣求得的所有攝氏溫度都將為0。從該例了中也可以看出printf函數(shù)的ー些功能。printf是ー個(gè)通用輸出格式化函數(shù),第7章將對(duì)此做詳細(xì)介紹。該函數(shù)的第一個(gè)參數(shù)是待打印的字符串,其中的每個(gè)百分號(hào)(%)表示其它的參數(shù)(第二個(gè)、第三個(gè) 參數(shù))之一進(jìn)行替換的位置,并指定打印格式。例如,%d指定一個(gè)整型參數(shù),因此語(yǔ)句printf("%d\t%d\n*,fahr,Celsius);用于打印兩個(gè)整數(shù)fahr與Celsius的值,并在兩者之間留一個(gè)制表符的空間(\t)。printf函數(shù)的第一個(gè)參數(shù)中的各個(gè)%分別對(duì)應(yīng)于第二個(gè)、第三個(gè) 參數(shù),它們?cè)跀?shù)I!和類型し都必須匹配,否則將出現(xiàn)錯(cuò)誤的結(jié)果。順便指出,printf函數(shù)并不是C語(yǔ)言本身的一部分,C語(yǔ)言本身并沒(méi)有定義輸入/輸出功能。printf僅僅是標(biāo)準(zhǔn)庫(kù)函數(shù)中一個(gè)有用的函數(shù)而已,這些標(biāo)準(zhǔn)序函數(shù)在C語(yǔ)言程序中通常都可以使用。但是,ANS!標(biāo)準(zhǔn)定義了printf函數(shù)的行為,因此,對(duì)每個(gè)符合該標(biāo)準(zhǔn)的編譯器和庫(kù)來(lái)說(shuō),該函數(shù)的屬性都是相同的。為了將重點(diǎn)放到講述C語(yǔ)言本身上,我們?cè)诘?章之前的各章中將不再對(duì)輸入/輸出做更多的介紹,并且,特別將格式化輸入推后到第7章講解。如果讀者想了解數(shù)據(jù)輸入,可以先閱讀7.4節(jié)中對(duì)scanf函數(shù)的討論部分,scanf函數(shù)類似于printf函數(shù),但它用于讀輸入數(shù)據(jù)而不是寫(xiě)輸出數(shù)據(jù)。上述的溫度轉(zhuǎn)換程序存在兩個(gè)問(wèn)題。比較簡(jiǎn)單的問(wèn)題是,由于輸出的數(shù)不是右對(duì)齊的,所以輸出的結(jié)果不是很美觀。這個(gè)問(wèn)題比較容易解決:如果在printf語(yǔ)句的第一個(gè)參數(shù)的%d中指明打印寬度,則打印的數(shù)字會(huì)在打印區(qū)域內(nèi)右對(duì)齊。例如,可以用語(yǔ)句printf(*%3d%6d\n”,fahr,Celsius);打印fahr與Celsius的值,這樣,fahr的值占3個(gè)數(shù)字寬,Celsius的值占6個(gè)數(shù)字寬,輸出的結(jié)果如下所示,0 -1720-640460ー個(gè)較為嚴(yán)重的問(wèn)題是,由于我們使用的是整型算術(shù)運(yùn)算,因此經(jīng)計(jì)算得到的攝氏溫度值不太精確,例如,與0T對(duì)應(yīng)的精確的攝氏溫度應(yīng)該為ー17.8°C,而不是ー17°Co為了得到更精確的結(jié)果,應(yīng)該用浮點(diǎn)算術(shù)運(yùn)算代替上面的整型算術(shù)運(yùn)算。這就需要對(duì)程序做適當(dāng)修改。ド而是該程序的又一種版本^include<stdio.h>/*printFahrenheit-Celsiustableformain()fahr=0,20,...,300;floating-pointversionfloatfahr,Celsius;floatlower,upper,steplower二0;/*lowerlimitoftemperatuirescaleupper=300;/*upper1imit*/step=fahr==20;=lower/*stepsize*/while(fahr<=upper){Celsius二=(5.0/9.0)*(fahr-32.0);printf("%3.Of%6.lf\n”,fahr,Celsius);;fahr=fahr+step;這個(gè)程序與前ー個(gè)程序基本相同,不同的是,它把fahr與Celsius聲明為float類型,轉(zhuǎn)換公式的表述方式也更自然ー些。在前ー個(gè)程序中,之所以不能使用5/9的形式,是因?yàn)榘凑统ǖ挠?jì)算規(guī)則,它們相除并舍位后得到的結(jié)果為。。但是,常數(shù)中的小數(shù)點(diǎn)表明該常數(shù)是ー個(gè)浮點(diǎn)數(shù),因此,5.0/9.0是兩個(gè)浮點(diǎn)數(shù)相除,結(jié)果將不被舍位。如果某個(gè)算術(shù)運(yùn)算符的所冇操作數(shù)均為整型,則執(zhí)行整型運(yùn)算。但是,如果某個(gè)算術(shù)運(yùn)算符有一個(gè)浮點(diǎn)型操作數(shù)和一個(gè)整型操作數(shù),則在開(kāi)始運(yùn)算之前整型操作數(shù)將會(huì)被轉(zhuǎn)換為浮點(diǎn)型。例如,在表達(dá)式fahr-32中,32在運(yùn)算過(guò)程中將被自動(dòng)轉(zhuǎn)換為浮點(diǎn)數(shù)再參與運(yùn)算。不過(guò),即使浮點(diǎn)常量取的是整型值,在書(shū)寫(xiě)時(shí)最好還是為它加上一個(gè)顯式的小數(shù)點(diǎn),這樣可以強(qiáng)調(diào)其浮點(diǎn)性質(zhì),便于閱讀。第2章將詳細(xì)介紹把整型數(shù)轉(zhuǎn)換為浮點(diǎn)型數(shù)的規(guī)則。在這里需要注意,賦值語(yǔ)句fahr=lower;與條件測(cè)試語(yǔ)句while(fahr<=upper)也都是按照這種方式執(zhí)行的,即在運(yùn)算之前先把int類型的操作數(shù)轉(zhuǎn)換為float類型的操作數(shù)。printf中的轉(zhuǎn)換說(shuō)明%3.Of表明待打印的浮點(diǎn)數(shù)(即fahr)至少占3個(gè)字符寬,且不帶小數(shù)點(diǎn)和小數(shù)部分;%6.If表明另ー個(gè)待打印的數(shù)(Celsius)至少占6個(gè)字符寬,且小數(shù)點(diǎn)后面有1位數(shù)字。其輸岀如下所示:0 -17.820-6.7404.4格式說(shuō)明可以省略寬度與精度,例如,%6f表示待打印的浮點(diǎn)數(shù)至少有6個(gè)字符寬;%.2f指定待打印的浮點(diǎn)數(shù)的小數(shù)點(diǎn)后有兩位小數(shù),但寛度沒(méi)有限制;%f則僅僅要求按照浮點(diǎn)數(shù)打印該數(shù)。%d 按照十進(jìn)制整型數(shù)打印%6d 按照十進(jìn)制整型數(shù)打印,至少6個(gè)字符寬%f 按照浮點(diǎn)數(shù)打印%6f 按照浮點(diǎn)數(shù)打印,至少6個(gè)字符寬%.2f按照浮點(diǎn)數(shù)打印,小數(shù)點(diǎn)后有兩位小數(shù)%6.2f按照浮點(diǎn)數(shù)打印,至少6個(gè)字符寬,小數(shù)點(diǎn)后有兩位小數(shù)此外,printf函數(shù)還支持下列格式說(shuō)明:%。表示八進(jìn)制數(shù);%x表示十六進(jìn)制數(shù);%c表不字符;%s表不字符串;%%表不百分號(hào)(%)本身。練習(xí)1-3修改溫度轉(zhuǎn)換程序,使之能在轉(zhuǎn)換表的頂部打印ー個(gè)標(biāo)題。練習(xí)1-4編寫(xiě)ー個(gè)程序打印攝氏溫度轉(zhuǎn)換為相應(yīng)華氏溫度的轉(zhuǎn)換表。for語(yǔ)句對(duì)于某個(gè)特定任務(wù)我們可以采用多種方法來(lái)編寫(xiě)程序。下面這段代碼也可以實(shí)現(xiàn)前面的溫度轉(zhuǎn)換程序的功能:/?打印華氏溫度ー攝氏溫度對(duì)照表?/main()(intfahr;for(fahr=0;fahr<=300;fahr=fahr+20)printf("%3d%6.lf\n*,fahr,(5.0/9.0)*(fahr-32));}這個(gè)程序與上節(jié)中介紹的程序執(zhí)行結(jié)果相同,但程序本身卻有所不同。最主要的改進(jìn)在于它去掉了大部分變量,而只使用了一個(gè)int類型的變量fahr。在新引入的for語(yǔ)句中,溫度的下限、上限和步長(zhǎng)都是常量,而計(jì)算攝氏溫度的表達(dá)式現(xiàn)在變成了printf函數(shù)的第三個(gè)參數(shù),它不再是ー個(gè)單獨(dú)的賦值語(yǔ)句。以上幾點(diǎn)改進(jìn)中的最后一點(diǎn)是C語(yǔ)言中一個(gè)通用規(guī)則的實(shí)例,在允許使用某種類型變量值的任何場(chǎng)合,都可以使用該類型的更復(fù)雜的表達(dá)式。因?yàn)閜rintf函數(shù)的第三個(gè)參數(shù)必須是與%6.If匹配的浮點(diǎn)值,所以可以在此處使用任何浮點(diǎn)表達(dá)式。for語(yǔ)句是一種循環(huán)語(yǔ)句,它是對(duì)whi1e語(yǔ)句的推廣。如果將for語(yǔ)句與前面介紹的while語(yǔ)句比較,就會(huì)發(fā)現(xiàn)for語(yǔ)句的操作更直觀ー些。圓括號(hào)中共包含3個(gè)部分,各部分之間用分號(hào)隔開(kāi)。第一部分fahr=0是初始化部分,僅在進(jìn)入循環(huán)前執(zhí)行一次。第二部分fahr<=300是控制循環(huán)的測(cè)試或條件部分。循環(huán)控制將對(duì)該條件求值,如果結(jié)果值為真(true),則執(zhí)行循環(huán)體(本例中的循環(huán)體僅包含ー個(gè)printf函數(shù)調(diào)用語(yǔ)句)。此后將執(zhí)行第三部分fahr=fahr+20以將循環(huán)變量fahr增加一個(gè)步長(zhǎng),并再次對(duì)條件求值。如果計(jì)算得到的條件值為假(faise),循環(huán)將終止執(zhí)行。與while語(yǔ)句ー樣,for循環(huán)語(yǔ)句的循環(huán)體可以只有一條語(yǔ)句,也可以是用花括號(hào)括起來(lái)的ー組語(yǔ)句。初始化部分(第一部分)、條件部分(第二部分)與增加步長(zhǎng)部分(第三部分)都可以是任何表達(dá)式。在實(shí)際編程過(guò)程中,可以選擇while與for中的任意ー種循環(huán)語(yǔ)句,主要要看使用哪ー種更淸晰。for語(yǔ)句比較適合初始化和增加步長(zhǎng)都是單條語(yǔ)句并且邏輯相關(guān)的情形,因?yàn)樗鼘⒀h(huán)控制語(yǔ)句集中放在一起,且比while語(yǔ)句更緊湊。練習(xí)1-5修改溫度轉(zhuǎn)換程序,要求以逆序(即按照從300度到〇度的順序)打印溫度轉(zhuǎn)換表。符號(hào)常量在結(jié)束討論溫度轉(zhuǎn)換程序前,我們?cè)賮?lái)看一下符號(hào)常量。在程序中使用300、20等類似的“幻數(shù)”并不是一個(gè)好習(xí)慣,它們幾乎無(wú)法向以后閱讀該程序的人提供什么信息,而且使程序的修改變得更加困難。處理這種幻數(shù)的ー種方法是賦予它們有意義的名字。#define指令可以把符號(hào)名(或稱為符號(hào)常量)定義為ー個(gè)特定的字符串:#define名字替換文本在該定義之后,程序中出現(xiàn)的所有在#46上1卩6中定義的名字(既沒(méi)有用引號(hào)引起來(lái),也不是其它名字的一部分)都將用相應(yīng)的替換文本替換。其中,名字與普通變量名的形式相同:它們都是以字母打頭的字母和數(shù)字序列:替換文本可以是任何字符序列,而不僅限于數(shù)字。#inc1ude<stdio.h>ttdefineLOWER0^defineUPPER300#defineSTEP20/*lowerlimitoftable*//*upperlimit*/ttdefineLOWER0^defineUPPER300#defineSTEP20/*lowerlimitoftable*//*upperlimit*//*stepsize*//*printFahrenheit-Celsiustable*/main()(intfahr;for(fahr=LOWER;fahr<=UPPER;fahr=fahr+STEP)printf(43d%6.lf\n”,fahr,(5.0/9.0)*(fahr-32));其中,LOWER.UPPER與STEP都是符號(hào)常量,而非變量,因此不需要出現(xiàn)在聲明中。符號(hào)常量名通常用大寫(xiě)字母拼寫(xiě),這樣可以很容易與用小寫(xiě)字母拼寫(xiě)的變量名相區(qū)別。注意,#define指令行的末尾沒(méi)有分號(hào)。字符輸入/輸出接下來(lái)我們看ー組與字符型數(shù)據(jù)處理有關(guān)的程序。讀者將會(huì)發(fā)現(xiàn),許多程序只不過(guò)是這里所討論的程序原型的擴(kuò)充版本而已。標(biāo)準(zhǔn)庫(kù)提供的輸入/輸出模型非常簡(jiǎn)單。無(wú)論文本從何處輸入,輸出到何處,其輸入/輸出都是按照字符流的方式處理。文本流是由多行字符構(gòu)成的字符序列,而每行字符則由〇個(gè)或多個(gè)字符組成,行末是ー個(gè)換行符。標(biāo)準(zhǔn)庫(kù)負(fù)責(zé)使每個(gè)輸入/輸出流都能夠遵守這一?模型。使用標(biāo)準(zhǔn)庫(kù)的c語(yǔ)言程序員不必關(guān)心在程序之外這些行是如何表示的。標(biāo)準(zhǔn)庫(kù)提供了一次讀/寫(xiě)ー個(gè)字符的函數(shù),其中最簡(jiǎn)單的是getchar和putchar兩個(gè)函數(shù)。每次調(diào)用時(shí),getchar函數(shù)從文本流中讀入下ー個(gè)輸入字符,并將其作為結(jié)果值返回。也就是說(shuō),在執(zhí)行語(yǔ)句c=getchar()之后,變量c中將包含輸入流中的下ー個(gè)字符。這種字符通常是通過(guò)鍵盤(pán)輸入的。關(guān)于從文件輸入字符的方法,我們將在第7章中討論。每次調(diào)用putchar函數(shù)時(shí)將打印ー個(gè)字符。例如,語(yǔ)句putchar()將把整型變量c的內(nèi)容以字符的形式打印出來(lái),通常是顯不在屏幕I二。putchar與printf這兩個(gè)函數(shù)可以交替調(diào)用,輸出的次序與調(diào)用的次序一致。借助于getchar與putchar函數(shù),可以在不了解其它輸入/輸岀知識(shí)的情況下編寫(xiě)出數(shù)量驚人的有用的代碼。最簡(jiǎn)單的例子就是把輸入一次一個(gè)字符地復(fù)制到輸出,其基本思想如下:讀ー個(gè)字符while(該字符不是文件結(jié)束指示符)輸出剛讀入的字符讀下ー個(gè)字符將上述基本思想轉(zhuǎn)換為C語(yǔ)言程序?yàn)???include<stdio.h>/*copyinputtooutput;1stversion*/main()c=getchar();while(c!=EOF){putchar(c);c=getchar();其中,關(guān)系運(yùn)算符!=表示“不等于”。字符在鍵盤(pán)、屏幕或其它的任何地方無(wú)論以什么形式表現(xiàn),它在機(jī)器內(nèi)部都是以位模式存儲(chǔ)的。char類型專門(mén)用于存儲(chǔ)這種字符型數(shù)據(jù),當(dāng)然任何整型(int)也可以用于存儲(chǔ)字符型數(shù)據(jù)。因?yàn)槟承撛诘闹匾?,我們?cè)诖耸褂胕nt類型。這里需要解決如何區(qū)分文件中有效數(shù)據(jù)與輸入結(jié)束符的問(wèn)題。C語(yǔ)言采取的解決方法是:在沒(méi)有輸入時(shí),getchar函數(shù)將返回一個(gè)特殊值,這個(gè)特殊值與任何實(shí)際字符都不同。這個(gè)值稱為EOF(endoffile,文件結(jié)束)。我們?cè)诼暶髯兞縞的時(shí)候,必須讓它大到足以存放getchar函數(shù)返回的任何值。這里之所以不把c聲明成char類型,是因?yàn)樗仨氉銐虼?除了能存儲(chǔ)任何可能的字符外還要能存儲(chǔ)文件結(jié)束符EOF。因此,我們將c聲明成int類型。EOF定義在頭文件〈stdio.h>*,是個(gè)整型數(shù),其具體數(shù)值是什么并不重要,只要它與任何char類型的值都不相同即可。這里使用符號(hào)常量,可以確保程序不需要依賴于其對(duì)應(yīng)的任何特定的數(shù)值。對(duì)于經(jīng)驗(yàn)比較豐富的C語(yǔ)言程序員,可以把這個(gè)字符復(fù)制程序編寫(xiě)得更精煉一些。在。語(yǔ)言中,類似于c=getchar()之類的賦值操作是一個(gè)表達(dá)式,并且具有一個(gè)值,即賦值后左邊變量保存的值。也就是說(shuō),賦值可以作為更大的表達(dá)式的一部分出現(xiàn)。如果將為c賦值的操作放在while循環(huán)語(yǔ)句的測(cè)試部分中,上述字符復(fù)制程序便可以改寫(xiě)成下列形式,/*copyinputtooutput;2ndversion*/main(){,intc;while((c=getchar())!=EOF)putchar(c);}在該程序中,while循環(huán)語(yǔ)句首先讀ー個(gè)字符并將其賦值給c然后測(cè)試該字符是否為文件結(jié)束標(biāo)志。如果該字符不是文件結(jié)束標(biāo)志,則執(zhí)行while語(yǔ)句體,并打印該字符。隨后重復(fù)執(zhí)行while語(yǔ)句。當(dāng)?shù)竭_(dá)輸入的結(jié)尾位置時(shí),while循環(huán)語(yǔ)句終止執(zhí)行,從而整個(gè)main函數(shù)執(zhí)行結(jié)束。以上這段程序?qū)⑤斎爰谢?getchar函數(shù)在程序中只出現(xiàn)了一次,這樣就縮短了程序,整個(gè)程序看起來(lái)更緊湊。習(xí)慣這種風(fēng)格后,讀者就會(huì)發(fā)現(xiàn)按照這種方式編寫(xiě)的程序更易閱讀。我們經(jīng)常會(huì)看到這種風(fēng)格。(不過(guò),如果我們過(guò)多地使用這種類型的復(fù)雜語(yǔ)句,編寫(xiě)的程序可能會(huì)很難理解,應(yīng)盡量避免這種情況。)對(duì)while語(yǔ)句的條件部分來(lái)說(shuō),賦值表達(dá)式兩邊的圓括號(hào)不能省略。不等于運(yùn)算符!=的優(yōu)先級(jí)比賦值運(yùn)算符=的優(yōu)先級(jí)要髙,這樣,在不使用圓括號(hào)的情況下關(guān)系測(cè)試!=將在賦值=操作之前執(zhí)行。因此語(yǔ)句c=getchar()!=EOF等價(jià)于語(yǔ)句c=(getchar()!=EOF)該語(yǔ)句執(zhí)行后,c的值將被置為0或1(取決于調(diào)用getchar函數(shù)時(shí)是否碰到文件結(jié)束標(biāo)志),這并不是我們所希望的結(jié)果(更詳細(xì)的內(nèi)容,請(qǐng)參見(jiàn)第2章的相關(guān)部分)。練習(xí)1-6驗(yàn)證表達(dá)式getchar()!=EOF的值是〇還是1。練習(xí)1-7編寫(xiě)ー個(gè)打印EOF值的程序。1.5.2.字符計(jì)數(shù)下列程序用于對(duì)字符進(jìn)行計(jì)數(shù),它與上面的復(fù)制程序類似。0include<stdio.h>/*countcharactersininput;1stversion*/main()(longnc;while(getchar()!=EOF)++nc;printf(*%ld\n*,nc);其中,語(yǔ)句++nc;引入了一個(gè)新的運(yùn)算符++,其功能是執(zhí)行加1操作??梢杂谜Z(yǔ)句nc=nc+1代替它,但語(yǔ)句++nc更精煉ー些,且通常效率也更髙。與該運(yùn)算符相應(yīng)的是自減運(yùn)算符ー。++與一這兩個(gè)運(yùn)算符既可以作為前綴運(yùn)算符(如++nc),也可以作為后綴運(yùn)算符(如nc++)。我們?cè)诘?章中將看到,這兩種形式在表達(dá)式中具有不同的值,但++nc與nc++都使nc的值增加!.目前,我們只使用前綴形式。該字符計(jì)數(shù)程序使用long類型的變量存放計(jì)數(shù)值,而沒(méi)有使用int類型的變量。long整型數(shù)(長(zhǎng)整型)至少要占用32位存儲(chǔ)單元。在某些機(jī)器上int與!ong類型的長(zhǎng)度相同,但在ー些機(jī)器上,int類型的值可能只有16位存儲(chǔ)單元的長(zhǎng)度(最大值為32767),這樣,相當(dāng)小的輸入都可能使int類型的計(jì)數(shù)變量溢出。轉(zhuǎn)換說(shuō)明%Id告訴printf函數(shù)其對(duì)應(yīng)的參數(shù)是long整型。使用double(雙精度浮點(diǎn)數(shù))類型可以處理更大的數(shù)字。我們?cè)谶@里不使用while循環(huán)語(yǔ)句,面用for循環(huán)語(yǔ)句來(lái)展示編寫(xiě)此循環(huán)的另ー種方法,^include<stdio.h>/*countcharactersininput;2ndversion*/main(){doublenc;for(nc=0;gechar()!=EOF;++nc)printf("虬Of\n”,nc);}對(duì)于float與double類型。printf函數(shù)都使用%f進(jìn)行說(shuō)明。%.Of強(qiáng)制不打印小數(shù)點(diǎn)和小數(shù)部分,因此小數(shù)部分的位數(shù)為〇。在該程序段中,for循環(huán)語(yǔ)句的循環(huán)體是空的,這是因?yàn)樗泄ぷ鞫荚跍y(cè)試(條件)部分與增加步長(zhǎng)部分完成了。但C語(yǔ)言的語(yǔ)法規(guī)則要求for循環(huán)語(yǔ)句必須有一個(gè)循環(huán)體,因此用單獨(dú)的分號(hào)代替。單獨(dú)的分號(hào)稱為空語(yǔ)句,它正好能滿足for語(yǔ)句的這ー要求。把它單獨(dú)放在一行是為了更加醒目。在結(jié)束討論字符計(jì)數(shù)程序之前,我們考慮以下情況,如果輸入中不包含字符,那么,在第一次調(diào)用getchar函數(shù)的叫候,while語(yǔ)句或for語(yǔ)句中的條件測(cè)試從ー開(kāi)始就為假,程序的執(zhí)行結(jié)果將為0,這也是正確的結(jié)果。這一點(diǎn)很重要。while語(yǔ)句與for語(yǔ)句的優(yōu)點(diǎn)之一就是在執(zhí)行循環(huán)體之前就對(duì)條件進(jìn)行測(cè)試,如果條件不滿足,則不執(zhí)行循環(huán)體,這就可能出現(xiàn)循環(huán)體一次都不執(zhí)行的情況。在出現(xiàn)〇長(zhǎng)度的輸入時(shí),程序的處理應(yīng)該靈活ー些,在出現(xiàn)邊界條件時(shí),while語(yǔ)句與for語(yǔ)句有助于確保程序執(zhí)行合理的操作。1.5.3.行計(jì)數(shù)接下來(lái)的這個(gè)程序用于統(tǒng)計(jì)輸入中的行數(shù)。我們?cè)谏厦嫣岬竭^(guò),標(biāo)準(zhǔn)庫(kù)保證輸入文本流以行序列的形式出現(xiàn),每一行均以換行符結(jié)束。因此,統(tǒng)計(jì)行數(shù)等價(jià)于統(tǒng)計(jì)換行符的個(gè)數(shù)。/*countlinesininput*/main()(intc,nl;nl=0;while((c=getcharO)!=EOF)if(c==,ヽn')++nl;printf("%d\n",nl);}在該程序中,while循環(huán)語(yǔ)句的循環(huán)體是ー個(gè)if語(yǔ)句,它控制自増語(yǔ)句++nl。if語(yǔ)句先測(cè)試圓括號(hào)中的條件,如果該條件為真,則執(zhí)行其后的語(yǔ)句(或括在花括號(hào)中的ー組語(yǔ)句)。這里再次用縮進(jìn)方式表明語(yǔ)句之間的控制關(guān)系。雙等于號(hào)==是C語(yǔ)言中表示“等于"關(guān)系的運(yùn)算符(類似于Pascal中的單等于號(hào)=及Fortran中的.EQ.)。由于C語(yǔ)言將單等于號(hào)=作為賦值運(yùn)算符,因此使用雙等于號(hào)==表示相等的邏輯關(guān)系,以示區(qū)分。這里提醒注意,在表示“等于"邏輯關(guān)系的時(shí)候(應(yīng)該用==),C語(yǔ)言初學(xué)者有時(shí)會(huì)錯(cuò)誤地寫(xiě)成單等于號(hào)ー在第2章我們將看到,即使這樣誤用了,其結(jié)果通常仍然是合法的表達(dá)式,因此系統(tǒng)不會(huì)給出警告信息。單引號(hào)中的字符表示一個(gè)整型值,該值等于此字符在機(jī)器字符集中對(duì)應(yīng)的數(shù)值,我們稱之為字符常量。但是,它只不過(guò)是小的整型數(shù)的另ー種寫(xiě)法而已。例如,'是一個(gè)字符常量;在ASCII字符集中其值為65(即字符A的內(nèi)部表示值為65)。當(dāng)然,用‘A’要比用65好,因?yàn)椤!瓵’的意義更清楚,且與特定的字符集無(wú)關(guān)。字符串常量中使用的轉(zhuǎn)義字符序列也是合法的字符常量,比如,’、ガ代表?yè)Q行符的值,在ASCII字符集中其值為10。我們應(yīng)當(dāng)注意到,''n'是單個(gè)字符,在表達(dá)式中它不過(guò)是ー個(gè)整型數(shù)而已;而"'n”是ー個(gè)僅包含一個(gè)字符的字符串常量。有關(guān)字符串與字符之間的關(guān)系,我們將在第2章進(jìn)ー步討論。練習(xí)1-8編寫(xiě)ー個(gè)統(tǒng)計(jì)空格、制表符與換行符個(gè)數(shù)的程序。練習(xí)1-9編寫(xiě)一個(gè)將輸入復(fù)制到輸出的程序,并將其中連續(xù)的多個(gè)空格用一個(gè)空格代替。練習(xí)1-10編寫(xiě)ー個(gè)將輸入復(fù)制到輸出的程序,并將其中的制表符替換為't,把回退符替換為'b,把反斜杠替按為''。這樣可以將制表符和回退符以可見(jiàn)的方式顯示出來(lái)。5.4.單詞計(jì)數(shù)我們將介紹的笫4個(gè)實(shí)用程序用于統(tǒng)計(jì)行數(shù)、單詞數(shù)與字符數(shù)。這里對(duì)單詞的定義比較寬松,它是任何其中不包含空格、制表符或換行符的字符序列。下面這段程序是UNIX系統(tǒng)中wc程序的骨干部分:#include<stdio.h>#defineIN1/*insideaword*/#defineOUT0/*outsideaword*//*count1ines,words,andcharactersininput?/main(){intc,nl,nw,nc,state;state=OUT;nl=nw=nc=0;while((c=getchar())!=EOF){++nc;if(c=='\n")++nl;if(c=="*||c=="\n*IIc='\t')state=OUT;elseif(state==OUT){state=IN;++nw;printf(飛d%d%d\n”,nl,nw,nc);)程序執(zhí)行時(shí),每當(dāng)遇到單詞的第一個(gè)字符,它就作為一個(gè)新單詞加以統(tǒng)計(jì)。state變量記錄程序當(dāng)前是否正位于ー個(gè)單詞之中,它的初值是“不在單詞中”,即初值被賦為OUT。我們?cè)谶@里使用了符號(hào)常量1N與OUT,而沒(méi)冇使用其對(duì)應(yīng)的數(shù)值1與0,這樣程序更易讀。在較小的程序中,這種做法也許看不出有什么優(yōu)勢(shì),但在較大的程序中,如果從一開(kāi)始就這樣做,因此而增加的一點(diǎn)工作量與提高程序可讀性帶來(lái)的好處相比是值得的。讀者也會(huì)發(fā)現(xiàn),如果程序中的幻數(shù)都以符號(hào)常量的形式出現(xiàn),對(duì)程序進(jìn)行大量修改就會(huì)相對(duì)容易得多。下列語(yǔ)句nl=nw=nc=0;將把其中的3個(gè)變量nl,nw與nc都設(shè)置為〇。這種用法很常見(jiàn),但要注意這樣ー個(gè)事實(shí):在兼有值與賦值兩種功能的表達(dá)式中,賦值結(jié)合次序是由右至左。所以上面這條語(yǔ)句等同于nl=(nw=(nc=0));運(yùn)算符丨丨代表OR(邏輯或),所以下列語(yǔ)句if(c==''||c==,、ゴIIc==''ピ)的意義是“如果。是空格,或c是換行符,或c是制表符”(前面講過(guò),轉(zhuǎn)義字符序列't是制表符的可見(jiàn)表示形式)。相應(yīng)地,運(yùn)算符&&代表AND(邏輯與),它僅比丨丨高ー個(gè)優(yōu)先級(jí)。由&&或丨丨連接的表達(dá)式由左至右求值,并保證在求值過(guò)程屮只要能夠判斷最終的結(jié)果為貞.或假,求值就立即終止。如果c是空格,則沒(méi)有必要再測(cè)試它是否為換行符或制表符,這樣就不必執(zhí)行后面兩個(gè)測(cè)試。在這里,這一點(diǎn)并不特別重要,但在某些更復(fù)雜的情況下這樣做就有必要了,不久我們將會(huì)看到這種例子。這段程序中還包括ー個(gè)else部分,它指定當(dāng)if語(yǔ)句中的條件部分為假時(shí)所要執(zhí)行的動(dòng)作.其ー般形式為:if(表述式)語(yǔ)句1else語(yǔ)句2其中,if-else中的兩條語(yǔ)句有且僅有一條語(yǔ)句被執(zhí)行。如果表達(dá)式的值為真,則執(zhí)行語(yǔ)句1,否則執(zhí)行語(yǔ)句2。這兩條語(yǔ)句都既可以是單條語(yǔ)句,也可以是括在花括號(hào)內(nèi)的語(yǔ)句序歹リ。在單詞計(jì)數(shù)程序中,else之后的語(yǔ)句仍是ー個(gè)if語(yǔ)句,該if語(yǔ)句控制了包含在花括號(hào)內(nèi)的兩條語(yǔ)句。練習(xí)!-1I你準(zhǔn)備如何測(cè)試單詞計(jì)數(shù)程序?如果程序中存在某種錯(cuò)誤,那么什么樣的輸入最可能發(fā)現(xiàn)這類錯(cuò)誤呢’練習(xí)!-12編寫(xiě)一個(gè)程序,以每行一個(gè)單詞的形式打印其輸入。1.6.數(shù)組在這部分內(nèi)容中,我們來(lái)編寫(xiě)ー個(gè)程序,以統(tǒng)計(jì)各個(gè)數(shù)字、空白符(包括空格符、制表符及換行符)以及所有其它字符出現(xiàn)的次數(shù)。這個(gè)程序的實(shí)用意義并不大,但我們可以通過(guò)該程序討論C語(yǔ)言多方面的問(wèn)題。所有的輸入字符可以分成12類,因此可以用一個(gè)數(shù)組存放各個(gè)數(shù)字出現(xiàn)的次數(shù),這樣比使用10個(gè)獨(dú)立的變量更方便。下面是該程序的ー種版本:#include<stdio.h>/*countdigits,whitespace,others*/main()(intc,i,nwhite,nother;intndigit[10];nwhite=nother=0;for(i=0;i<10;++i)ndigit[i]=0;while((c=getchar())!=EOF)if(c>=’〇'&&cく='9')++ndigit[c-'0'];elseif(cニニ''||c=='\n'IIc=='\t')++nwhite;else++nother;printf("digits=");for(i=0;i<10;++i)printf("%d",ndigit[i]);printf(",whitespace=%d,other=%d\n",nwhite,nother);}當(dāng)把這段程序本身作為輸入時(shí),輸出結(jié)果為.digits=9300000001,whitespace=123,other=345該程序中的聲明語(yǔ)句intndigit[10],將變量ndigit聲明為由10個(gè)整型數(shù)構(gòu)成的數(shù)組。在C語(yǔ)言中,數(shù)組下標(biāo)總是從〇開(kāi)始,因此該數(shù)組的10個(gè)元素分別為ndigit[0]、ndigit]い、…、ndigit[9],這可以通過(guò)初始化和打印數(shù)組的兩個(gè)for循環(huán)語(yǔ)句反映出來(lái)。數(shù)組下標(biāo)可以是任何整型表達(dá)式,包括整型變量(如i)以及整型常量。該程序的執(zhí)行取決于數(shù)字的字符表示屬性。例如,測(cè)試語(yǔ)句if(c>=’〇’&&c<=<9')用于判斷c中的字符是否為數(shù)字。如果它是數(shù)字,那么該數(shù)字對(duì)應(yīng)的數(shù)值是只有當(dāng)’〇’、T'、…、’9’具有連續(xù)遞增的值時(shí),這種做法オ可行。幸運(yùn)的是,所有的字符集都是這樣的。由定義可知,char類型的字符是小整型,因此char類型的變量和常量在算術(shù)表達(dá)式中等價(jià)于int類型的變量和常量。這樣做既自然又方便,例如,c-'Q'是ー個(gè)整型表達(dá)式,如果存儲(chǔ)在c中的字符是'〇'?’9',其值將為〇?9,因此可以充當(dāng)數(shù)組ndigit的合法下標(biāo)。判斷ー個(gè)字符是數(shù)字、空白符還是其它字符的功能可以由下列語(yǔ)句序列完成,if(c>='0'&&c<='9')++ndigit[c-'0'];elseif(c==''||c=='\n'iIc=='\t")++nwhite;else++nother;程序中經(jīng)常使用下列方式表示多路判定:if(條件D語(yǔ)句1elseif(條件1)語(yǔ)句2else語(yǔ)句n在這種方式中,各條件從前往后依次求值,直到滿足某個(gè)條件,然后執(zhí)行對(duì)應(yīng)的語(yǔ)句部分。這部分語(yǔ)句執(zhí)行完成后,整個(gè)語(yǔ)句體執(zhí)行結(jié)束(其中的任何語(yǔ)句都可以是括在花括號(hào)中的若干條語(yǔ)句)。如果所有條件都不滿足,則執(zhí)行位于最后ー個(gè)else之后的語(yǔ)句(如果有的話)。類似于前面的單詞計(jì)數(shù)程序,如果沒(méi)有最后一個(gè)else及對(duì)應(yīng)的語(yǔ)句,該語(yǔ)句體將不執(zhí)行任何動(dòng)作。在第一個(gè)if與最后一個(gè)else之間可以有0個(gè)或多個(gè)ド列形式的語(yǔ)句序列:就程序設(shè)計(jì)風(fēng)格而言,我們建議讀者采用上面所示的縮進(jìn)格式以體現(xiàn)該結(jié)構(gòu)的層次關(guān)系,否則,如果每個(gè)if都比前ー個(gè)else向里縮進(jìn)ー些距圏,那么較長(zhǎng)的判定序列就可能超出頁(yè)面的右邊界。第3章將討論的switch語(yǔ)句提供了編寫(xiě)多路分支程序的另ー種方式,它特別適合于判定某個(gè)整型或字符表達(dá)式是否與一個(gè)常量集合中的某個(gè)元素相匹配的情況。我們將在3.4節(jié)給出用switch語(yǔ)句編寫(xiě)的該程序的另ー個(gè)版本,與此進(jìn)行比較。練習(xí)!-13編寫(xiě)ー個(gè)程序,打印輸入中單詞長(zhǎng)度的直方圖。水平方向的直方圖比較容易繪制,垂直方向的有方圖則要困難些。練習(xí)!-14編寫(xiě)一個(gè)程序,打印輸入中各個(gè)字符出現(xiàn)頻度的直方圖。7.函數(shù)C語(yǔ)言中的函數(shù)等價(jià)于Fortran語(yǔ)言中的子程序或函數(shù),也等價(jià)于Pascal語(yǔ)言中的過(guò)程或函數(shù)。函數(shù)為計(jì)算的封裝提供了一種簡(jiǎn)便的方法,此后使用函數(shù)時(shí)不需要考慮它是如何實(shí)現(xiàn)的。使用設(shè)計(jì)正確的函數(shù),程序員無(wú)需考慮功能是如何實(shí)現(xiàn)的,而只需知道它具有哪些功能就夠了。在(:語(yǔ)言中可以簡(jiǎn)單、方便、髙效地使用函數(shù)。我們經(jīng)常會(huì)看到在定義后僅調(diào)用了一次的短函數(shù),這樣做可以使代碼段更清晰易讀。到F)前為止,我們所使用的函數(shù)(如printf、getchar和putchar等)都是函數(shù)庫(kù)中提供的函數(shù)?,F(xiàn)在,讓我們自己動(dòng)手來(lái)編寫(xiě)ー些函數(shù)。C語(yǔ)言沒(méi)冇像Fortran語(yǔ)言ー樣提供類似于??的求裏運(yùn)算符,我們現(xiàn)在通過(guò)編寫(xiě)ー個(gè)求器的函數(shù)power(m,n)來(lái)說(shuō)明函數(shù)定義的方法。power(m,n)函數(shù)用ア計(jì)算整數(shù)m的n次裏,其中n是正整數(shù)。對(duì)函數(shù)調(diào)用power(2,5)來(lái)說(shuō),其結(jié)果值為32。該函數(shù)并非ー個(gè)實(shí)用的求索函數(shù),它只能處理較小的整數(shù)的正整數(shù)次’恭,但這對(duì)于說(shuō)明問(wèn)題已足夠了。(標(biāo)準(zhǔn)庫(kù)中提供了一個(gè)計(jì)算X"的函數(shù)pow(x,y).)卜,面是函數(shù)power(m,n)的定義及調(diào)用它的主程序,這樣我們可以看到ー個(gè)完整的程序結(jié)構(gòu)。#include<stdio.h>intpower(intm,intn);/*testpowerfunction*/main()inti;for(i=0;i<10;++i)printf(*%d%d%d\n”,i,power(2,i),power(-3,i));return0;/*power:raisebaseton-thpower;n>=0*/intpower(intbase,intn)(inti,p;p=1;for(i=1;i<=n;++i)p=p*base:returnp;}函數(shù)定義的一般形式為:返回值類型函數(shù)名(0個(gè)或多個(gè)參數(shù)聲明)(聲明部分語(yǔ)句序列)函數(shù)定義可以以任意次序出現(xiàn)在ー個(gè)源文件或多個(gè)源文件中,但同一函數(shù)不能分割存放在多個(gè)文件中。如果源程序分散在多個(gè)文件中,那么,在編譯和加載時(shí),就需要做更多的工作,但這是操作系統(tǒng)的原因,并不是語(yǔ)言的屬性決定的。我們暫且假定將main和power這兩個(gè)函數(shù)放在同一文件中,這樣前面所學(xué)的有關(guān)運(yùn)行C語(yǔ)言程序的知識(shí)仍然冇效。main函數(shù)在下列語(yǔ)句中調(diào)用了兩次power函數(shù):printf(*%d%d%d\n”,i,power(2,i),power(~i,3)):每次調(diào)用時(shí),main函數(shù)向power函數(shù)傳遞兩個(gè)參數(shù);在調(diào)用執(zhí)行完成時(shí),power函數(shù)向main函數(shù)返回一個(gè)格式化的整數(shù)并打印。在表達(dá)式中,power(2,i)同2和iー樣都是整數(shù)(并不是所有函數(shù)的結(jié)果都是整型值,我們將在第4章中討論)。power函數(shù)的第一行語(yǔ)句intpower(intbase,intn)聲明參數(shù)的類型、名字以及該函數(shù)返回結(jié)果的類型。power函數(shù)的參數(shù)使用的名字只在power函數(shù)內(nèi)部有效,對(duì)其它任何函數(shù)都是不可見(jiàn)的:其它函數(shù)可以使用與之相同的參數(shù)名字而不會(huì)引起沖突。變量i與P也是這樣:power函數(shù)中的i與main函數(shù)中的i無(wú)關(guān)。我們通常把函數(shù)定義中圓括號(hào)內(nèi)列表中出現(xiàn)的變量稱為形式參數(shù),而把函數(shù)調(diào)用中與形式參數(shù)對(duì)應(yīng)的值稱為實(shí)際參數(shù)。power函數(shù)計(jì)算所得的結(jié)果通過(guò)return語(yǔ)句返回給main函數(shù)。關(guān)鍵字return的后面可以跟任何表達(dá)式,形式為:return表達(dá)式:函數(shù)不一定都有返回值。不帶表達(dá)式的return語(yǔ)句將把控制權(quán)返回給調(diào)用者,但不返回有用的值。這等同于在到達(dá)函數(shù)的右終結(jié)花括號(hào)時(shí),函數(shù)就“到達(dá)了盡頭”。主調(diào)函數(shù)也可以忽略函數(shù)返回的值。讀者可能已經(jīng)注意到,main函數(shù)的末尾有一個(gè)return語(yǔ)句。由于main本身也是函數(shù),因此也可以向其調(diào)用者返回一個(gè)值,該調(diào)用者實(shí)際上就是程序的執(zhí)行環(huán)境。一般來(lái)說(shuō),返回值為〇表示正常終止,返回值為非〇表示出現(xiàn)異常情況或出錯(cuò)結(jié)束條件。為簡(jiǎn)潔起見(jiàn),前面的main函數(shù)都省略了return語(yǔ)句,但我們將在以后的main函數(shù)中包含return語(yǔ)句,以提醒大家注意,程序還要向其執(zhí)行環(huán)境返冋狀態(tài)。出現(xiàn)在main函數(shù)之前的聲明語(yǔ)句intpower(intm,intn);表明power函數(shù)有兩個(gè)int類型的參數(shù),并返回一個(gè)int類型的值。這種聲明稱為函數(shù)原型,它必須與power函數(shù)的定義和用法一致。如果函數(shù)的定義、用法與函數(shù)原型不一致,將岀現(xiàn)錯(cuò)誤。函數(shù)原型與函數(shù)聲明中參數(shù)名不要求相同。事實(shí)匕函數(shù)原型中的參數(shù)名是可選的,這樣上面的函數(shù)原型也可以寫(xiě)成以下形式但是,合適的參數(shù)名能夠起到很好的說(shuō)明性作用,因此我們?cè)诤瘮?shù)原型中總是指明參數(shù)名?;仡櫼幌拢珹NSIC同較早版本C語(yǔ)言之間的最大區(qū)別在于函數(shù)的聲明與定義方式的不同。按照C語(yǔ)言的最初定義,power函數(shù)應(yīng)該寫(xiě)成下列形式:/*power:raisebaseton-thpower;n>=0*//* (old-styleversion)*/power(base,n)intbase,n;(inti,p:p=1;for(i=1;i<=n;++i)p=p*base;returnp;}其中,參數(shù)名在阿括號(hào)內(nèi)指定,參數(shù)類型在左花括號(hào)之前聲明。如果沒(méi)有聲明某個(gè)參數(shù)的類型,則默認(rèn)為int類型。函數(shù)體與ANSIC中形式相同。在C語(yǔ)言的最初定義中,可以在程序的開(kāi)頭按照下面這種形式聲明power函數(shù):intpower();函數(shù)聲明中不允許包含參數(shù)列表,這樣編譯器就無(wú)法在此時(shí)檢査power函數(shù)調(diào)用的合法性。事實(shí)上,power函數(shù)在默認(rèn)情況下將被假定返回int類型的值,因此整個(gè)函數(shù)的聲明可以全部省略。在ANSIC中定義的函數(shù)原型語(yǔ)法中,編譯器可以很容易檢測(cè)出函數(shù)調(diào)用中參數(shù)數(shù)目和類型方面的錯(cuò)誤。ANSIC仍然支持舊式的函數(shù)聲明與定義,這樣至少可以有一個(gè)過(guò)渡階段。但我們還是強(qiáng)烈建議讀者:在使用新式的編譯器時(shí),最好使用新式的函數(shù)原型聲明方式。練習(xí)1-15重新編寫(xiě)1.2節(jié)中的溫度轉(zhuǎn)換程序,使用函數(shù)實(shí)現(xiàn)溫度轉(zhuǎn)換計(jì)算。參數(shù)——傳值調(diào)用習(xí)慣其它語(yǔ)言(特別是Fortran語(yǔ)言)的程序員可能會(huì)對(duì)C語(yǔ)言的函數(shù)參數(shù)傳遞方式感到陌生。在C語(yǔ)言中,所有函數(shù)參數(shù)都是“通過(guò)值”傳遞的。也就是說(shuō),傳遞給被調(diào)用函數(shù)的參數(shù)值存放在臨時(shí)變量中,而不是存放在原來(lái)的變量中。這與其它某些語(yǔ)言是不同的,比如,F(xiàn)ortran等語(yǔ)言是“通過(guò)引用調(diào)用",Pascal則采用var參數(shù)的方式,在這些語(yǔ)言中,被調(diào)用的函數(shù)必須訪問(wèn)原始參數(shù),而不是訪問(wèn)參數(shù)的本地副本。最主要的區(qū)別在于,在C語(yǔ)言中,被調(diào)用函數(shù)不能直接修改主調(diào)函數(shù)中變量的值,而只能修改其私有的臨時(shí)副本的值。intpower(intzint);傳值調(diào)用的利大于弊。在被調(diào)用函數(shù)中,參數(shù)可以看作是便于初始化的局部變量,因此額外使用的變量更少。這樣程序可以更緊湊簡(jiǎn)潔。側(cè)如,下面的這個(gè)power函數(shù)利用了這ー性質(zhì):/*power:raisebaseton-thpower;n>=0;version2*/intpower(intbase,intn){intp;for(p=1;n>0;-n)p=p*base;returnp;}其中,參數(shù)n用作臨時(shí)變量,并通過(guò)隨后執(zhí)行的for循環(huán)語(yǔ)句遞減,直到其值為0,這樣就不需要額外引入變量i.power函數(shù)內(nèi)部對(duì)n的任何操作不會(huì)影響到調(diào)用函數(shù)中n的原始參數(shù)值。必要時(shí),也可以讓函數(shù)能夠修改主調(diào)函數(shù)中的變量。這種情況下,調(diào)用者需要向被調(diào)用函數(shù)提供待設(shè)置值的變量的地址(從技術(shù)角度看,地址就是指向變量的指針),而被調(diào)用函數(shù)則需要將対應(yīng)的參數(shù)聲明為指針類型,并通過(guò)它間接訪問(wèn)變量。我們將在第5章中討論指針。如果是數(shù)組參數(shù),情況就有所不同了。當(dāng)把數(shù)組名用作參數(shù)時(shí),傳遞給函數(shù)的值是數(shù)組起始元素的位置或地址ーー它并不復(fù)制數(shù)組元素本身。在被調(diào)用函數(shù)中,可以通過(guò)數(shù)組下標(biāo)訪問(wèn)或修改數(shù)組元索的值。這是下ー節(jié)將要討論的問(wèn)題。1.91字符數(shù)組字符數(shù)組是C語(yǔ)言中最常用的數(shù)組類型。下面我們通過(guò)編寫(xiě)ー個(gè)程序,來(lái)說(shuō)明字符數(shù)組以及操作字符數(shù)組的函數(shù)的用法。該程序讀入ー組文本行,并把最長(zhǎng)的文本行打印出來(lái)。該算法的基本框架非常簡(jiǎn)單:while(還有未處理的行)if(該行比已處理的最長(zhǎng)行還要長(zhǎng))保存該行為最長(zhǎng)行保存該行的長(zhǎng)度打印最長(zhǎng)的行從上面的框架中很容易看出,程序很自然地分成了若干片斷,分別用于讀入新行、測(cè)試讀入的行、保存該行,其余部分則控制這ー過(guò)程。因?yàn)檫@種劃分方式比較合理,所以可以按照這種方式編寫(xiě)程序。首先,我們編寫(xiě)ー個(gè)獨(dú)立的函數(shù)getline,它讀取輸入的下一行。我們盡量保持該函數(shù)在其它場(chǎng)臺(tái)也有用。至少getline函數(shù)應(yīng)該在讀到文件末尾時(shí)返回一個(gè)信號(hào);更為有用的設(shè)計(jì)是它能夠在讀入文本行時(shí)返回該行的長(zhǎng)度,而在遇到文件結(jié)束符時(shí)返回〇〇由于〇不是有效的行長(zhǎng)度,因此可以作為標(biāo)志文件結(jié)束的返冋值。每一行至少包括ー個(gè)字符,只包含換行符的行,其長(zhǎng)度為1。當(dāng)發(fā)現(xiàn)某個(gè)新讀入的行比以前讀入的最長(zhǎng)行還要長(zhǎng)時(shí),就需要把該行保存起來(lái)。也就是說(shuō),我們需要用另ー個(gè)函數(shù)copy把新行復(fù)制到一個(gè)安全的位置。最后,我們需要在主函數(shù)main中控制getline和copy這兩個(gè)函數(shù)。以下便是我們編寫(xiě)的程序:#include<stdio.h>#defineMAXLINE1000/*maximuminputlinelength*/intgetline(charline[],intmaxline);voidcopy(charto[],charfrom[]);/*printthelongestinputline*/main()intlen; /?currentlinelength*/intmax; /*maximumlengthseensofar*/charline[MAXLINE];/*currentinput1ine*/charIOngest[MAXLINE];/*longestlinesavedhere*/max=0;while((len=getline(line,MAXLINE))>0)if(len>max){max=len;copy(longest,1ine);}if(max>0)/*therewasaline*/printf("%s",longest);return0;/*getline:readalineintoints?returnlengthgetline(chars[],intlim){intc,i;for(i=0;i<lim-1&&(c=getchar())!=EOF&&c!=\n';++i)s[i]=c;if(c==,\n,){s[i]=c;++i;}s[i]=,\0,;returni;/*copy:copy,from,into'to';assumetoisbigenough*/voidcopy(charto[],charfrom[])(inti;while((to[i]=from[i])!=,\0,)++i;程序的開(kāi)始對(duì)getline和copy這兩個(gè)函數(shù)進(jìn)行了聲明,這里假定它們都存放在同一個(gè)文件中。main與getline之間通過(guò)?對(duì)參數(shù)及ー個(gè)返回值進(jìn)行數(shù)據(jù)交換。在getline函數(shù)中,兩個(gè)參數(shù)是通過(guò)程序行intgetline(chars[],int1im)聲明的,它把第一個(gè)參數(shù)s聲明為數(shù)組,把第二個(gè)參數(shù)lim聲明為整型,聲明中提供數(shù)組大小的目的是留出存儲(chǔ)空間。在getUne函數(shù)中沒(méi)有必要指明數(shù)組s的長(zhǎng)度,這是因?yàn)樵摂?shù)組的大小是在main函數(shù)中設(shè)置的。如同power函數(shù)ーー樣,getline函數(shù)使用了一個(gè)return語(yǔ)句將值返回給其調(diào)用者。上述程序行也聲明了getline數(shù)的返回值類型為int?由于函數(shù)的默認(rèn)返回值類型為int,因此這里的int可以省略。有些函數(shù)返回有用的值,而有些函數(shù)(如copy)僅用于執(zhí)行ー些動(dòng)作,并不返回值。copy函數(shù)的返回值類型為void,它顯式說(shuō)明該函數(shù)不返回任何值。getline函數(shù)把字符‘'0'(即空字符,其值為0)插入到它創(chuàng)建的數(shù)組的末尾,以標(biāo)記字符串的結(jié)束。這ー約定已被C語(yǔ)言采用:當(dāng)在C語(yǔ)言程序中出現(xiàn)類似于"hello\0"的字符串常量時(shí),它將以字符數(shù)組的形式存儲(chǔ),數(shù)組的各元素分別存儲(chǔ)字符串的各個(gè)字符,并以''0‘標(biāo)志字符串的結(jié)束。he11〇\n\0printf函數(shù)中的格式規(guī)范%s規(guī)定,對(duì)應(yīng)的參數(shù)必須是以這種形式表不的字符串。copy函數(shù)的實(shí)現(xiàn)正是依賴于輸入?yún)?shù)由’'0'結(jié)束這ー事實(shí),它將’'O'拷貝到輸出參數(shù)中。(也就是說(shuō),空字符''0'不是普通文本的一部分。)值得一提的是,即使是上述這樣很小的程序,在傳遞參數(shù)時(shí)也會(huì)遇到ー些麻煩的設(shè)計(jì)問(wèn)題。例如,當(dāng)讀入的行長(zhǎng)度大于允許的最大值時(shí),main函數(shù)應(yīng)該如何處理,getline函數(shù)的執(zhí)行是安全的,無(wú)論是否到達(dá)換行符字符,當(dāng)數(shù)組滿時(shí)它將停止讀字符。main函數(shù)可以通過(guò)測(cè)試行的長(zhǎng)度以及檢查返回的最后一個(gè)字符來(lái)判定當(dāng)前行是否太長(zhǎng),然后再根據(jù)具體的情況處理。為了簡(jiǎn)化程序,我們?cè)谶@里不考慮這個(gè)問(wèn)題。調(diào)用getline函數(shù)的程序無(wú)法預(yù)先知道輸入行的長(zhǎng)度,因此getline函數(shù)需要檢査是否溢出。另一方面,調(diào)用copy函數(shù)的程序知道(也可以找出)字符串的長(zhǎng)度,因此該函數(shù)不需要進(jìn)行錯(cuò)誤檢查。練習(xí)!-16修改打印最長(zhǎng)文本行的程序的主程序main,使之可以打印任意長(zhǎng)度的輸入行的長(zhǎng)度,并盡可能多地打印文本。練習(xí)177編寫(xiě)ー個(gè)程序,打印長(zhǎng)度大于80個(gè)字符的所有輸入行。練習(xí)!-18編寫(xiě)ー個(gè)程序,刪除每個(gè)輸入行末尾的空格及制表符,并刪除完全是空格的行。練習(xí)1-19編寫(xiě)函數(shù)reverse(s),將字符串s中的字符順序顛倒過(guò)來(lái)。使用該函數(shù)編寫(xiě)ー個(gè)程序,每次顛倒ー個(gè)輸入行中的字符順序。1.10.外部變量與作用域main函數(shù)中的變量(如1ine、longest等)是main函數(shù)的私自變量或局部變量。由于它們是在main函數(shù)中聲明的,因此其它函數(shù)不能直接訪問(wèn)它們。其它函數(shù)中聲明的變量也同樣如此。例如,getline函數(shù)中聲明的變量i與copy函數(shù)中聲明的變量i沒(méi)有關(guān)系。函數(shù)中的每個(gè)局部變量只在函數(shù)被調(diào)用時(shí)存在,在函數(shù)執(zhí)行完畢退出時(shí)消失。這也是其它語(yǔ)言通常把這類變量稱為自動(dòng)變最的原因。以后我們使用“自動(dòng)變量”代表“局部變量”。(第4章將討論static存儲(chǔ)類,這種類型的局部變量在多次函數(shù)調(diào)用之間保持值不變。)由于自動(dòng)變量只在函數(shù)調(diào)用執(zhí)行期間存在,因此,在函數(shù)的兩次調(diào)用之間,自動(dòng)變量不保留前次調(diào)用時(shí)的賦值,且在每次進(jìn)入函數(shù)時(shí)都要顯式為其賦值。如果自動(dòng)變量沒(méi)有賦值,則其中存放的是無(wú)效值。除自動(dòng)變量外,還可以定義位于所冇函數(shù)外部的變量,也就是說(shuō),在所有函數(shù)中都可以通過(guò)變量名訪問(wèn)這種類型的變量(這機(jī)制同F(xiàn)ortran語(yǔ)言中的COMMON變量或Pascal語(yǔ)言中最外層程序塊聲明的變量非常類似)。由丁一外部變量可以在全局范圍內(nèi)訪問(wèn),因此,函數(shù)間可以通過(guò)外部變量交換數(shù)據(jù),而不必使用參數(shù)表。再者,外部變量在程序執(zhí)行期間一直存在,而不是在函數(shù)調(diào)用時(shí)產(chǎn)生、在函數(shù)執(zhí)行完畢時(shí)消失。即使在對(duì)外部變量賦值的函數(shù)返回后,這些變量仍將保持原來(lái)的值不變。外部變量必須定義在所有函數(shù)之外,且只能定義一次,定義后編譯程序?qū)樗峙浯鎯?chǔ)單元。在每個(gè)需要訪問(wèn)外部變量的函數(shù)中,必須聲明相應(yīng)的外部變量,此時(shí)說(shuō)明其類型。聲明時(shí)可以用extern語(yǔ)句顯式聲明,也可以通過(guò)上ド文隱式聲明。為了更詳細(xì)地討論外部變量,我們改寫(xiě)上述打印最長(zhǎng)文本行的程序,把line、longest與max聲明成外部變量。這需要修改這3個(gè)函數(shù)的調(diào)用、聲明與函數(shù)體。intgetline(void);voidcopy(void);/*printlongestinputline;specializedversion*/main()(intlen;externintmax;externcharlongest[];max=0;while((len=getline())>0)if(len>max){max=len;copy();)if(max>0)/?therewasaline*/printf('%s",longest);return0;/*getline:specializedversion*/intget1ine(void)(intc,i;externchar1ine[];for(i=0;i<MAXLINE-1&&(c=getchar))!=EOF&&c!='\n';++i)1ine[i]=c;if(c=='\n'){1ine[i]=c;++i;1ine[i]=‘、〇';returni;/*copy:specializedversion*/voidcopy(void)(inti;externchar1ine[],longest[];while((longest[i]=line[i])!=‘、〇')++i;在該例子中,前幾行定義了main、getline與copy函數(shù)使用的幾個(gè)外部變量,聲明了各外部變量的類型,這樣編譯程序?qū)樗鼈兎峙浯鎯?chǔ)單元。從語(yǔ)法角度看,外部變量的定義與H部變量的定義是相同的,但由于它們位于各函數(shù)的外部,因此這些變量是外部變量。函數(shù)在使用外部變量之前,必須要知道外部變量的名字。要達(dá)到該目的,ー種方式是在函數(shù)中使用extern類型的聲明。這種類型的聲明除了在前面加了一個(gè)關(guān)鍵字externタト,其它方面與普通變量的聲明相同。某些情況下可以省略extern聲明。在源文件中,如果外部變量的定義出現(xiàn)在使用它的函數(shù)之前,那么在那個(gè)函數(shù)中就沒(méi)有必要使用extern聲明。因此,main、getline及copy中的幾個(gè)extern聲明都是多余的。在通常的做法中,所冇外部變量的定義都放在源文件的開(kāi)始處,這樣就可以省略extern聲明。如果程序包含在多個(gè)源文件中,而某個(gè)變量在filel文件中定義、在file2和file3文件中使用,那么在文件file2與file3中就需要使用extern聲明來(lái)建立該變量與其定義之間的聯(lián)系。人們通常把變量和函數(shù)的extern聲明放在ー個(gè)單獨(dú)的文件中(習(xí)慣上稱之為頭文件),并在每個(gè)源文件的開(kāi)頭使用#include語(yǔ)句把所要用的頭文件包含進(jìn)來(lái)。后綴名.h約定為頭文件名的擴(kuò)展名。例如,標(biāo)準(zhǔn)庫(kù)中的函數(shù)就是在類似于〈stdio.h〉的頭文件中聲明的。更詳細(xì)的信息將在第4章中討論,第7章及附錄B將討論函數(shù)庫(kù)。在上述特別版本中,由于getline與copy函數(shù)都不帶參數(shù),因此從邏輯上.講,在源文件開(kāi)始處它們的原型應(yīng)該是getlineO與copy。。但為了與老版本的C語(yǔ)言程序兼容,ANSIC語(yǔ)言把空參數(shù)表看成老版本C語(yǔ)言的聲明方式,并且對(duì)參數(shù)表不再進(jìn)行任何檢查。在ANSIC中,如果要聲明空參數(shù)表,則必須使用關(guān)鍵字void進(jìn)行顯式聲明。笫4章將對(duì)此進(jìn)ー步討論。讀者應(yīng)該注意到,這節(jié)中我們?cè)谡務(wù)撏獠孔兞繒r(shí)謹(jǐn)慎地使用了定義(define)與聲明(declaration)這兩個(gè)詞。“定義”表示創(chuàng)建變量或分配存儲(chǔ)單元,而“聲明”指的是說(shuō)明變量的性質(zhì),但并不分配存儲(chǔ)單元。順便提一下,現(xiàn)在越來(lái)越多的人把用到的所有東西都作為外部變量使用,因?yàn)樗坪踹@樣可以簡(jiǎn)化數(shù)據(jù)的通信ーー參數(shù)表變短了,且在需要時(shí)總可以訪問(wèn)這些變量。但是,即使在不使用外部變量的時(shí)候,它們也是存在的。過(guò)分依賴外部變量會(huì)導(dǎo)致一定的風(fēng)險(xiǎn),因?yàn)樗鼤?huì)使程序中的數(shù)據(jù)關(guān)系模糊不清ーー外部變量的值可能會(huì)被意外地或不經(jīng)意地修改,而程序的修改乂變得十分困難。我們前面編寫(xiě)的打印最長(zhǎng)文本行的程序的第2個(gè)版本就不如第1個(gè)版本好,原因有兩方面,其一便是使用了外部變量;另ー方面,第2個(gè)版本中的函數(shù)將它們所操縱的變量名宜接寫(xiě)入了函數(shù),從而使這兩個(gè)有用的函數(shù)失去了通用性。到目前為止,我們已經(jīng)對(duì)C語(yǔ)言的傳統(tǒng)核心部分進(jìn)行了介紹。借助于這些少量的語(yǔ)言元素,我們已經(jīng)能夠編寫(xiě)出相當(dāng)規(guī)模的有用的程序。建議讀者花ー些時(shí)間編寫(xiě)程序作為練習(xí)。ド面的幾個(gè)練習(xí)比本章前面編寫(xiě)的程序要復(fù)雜ーー些。練習(xí)1-20編寫(xiě)程序detab,將輸入中的制表符替換成適當(dāng)數(shù)目的空格,使空格充滿到下ー個(gè)制表符終止位的地方。假設(shè)制表符終止位的位置是固定的,比如每隔n列就會(huì)出現(xiàn)ー個(gè)制表符終止位。n應(yīng)該作為變量還是符號(hào)常量呢?練習(xí)1-21編寫(xiě)程序entab,將空格串替換為最少數(shù)量的制表符和空格,但要保持單詞之間的間隔不變。假設(shè)制表符終止位的位置與練習(xí)1-20的detab程序的情況相同。當(dāng)使用一個(gè)制表符或者ー個(gè)空格都可以到達(dá)下ー個(gè)制表符終止位時(shí),選用哪ー種替換字符比較好?練習(xí)!-22編寫(xiě)一個(gè)程序,把較長(zhǎng)的輸入行“折”成短一些的兩行或多行,折行的位置在輸入行的第n列之前的最后ー個(gè)非空格之后。要保證程序能夠智能地處理輸入行很長(zhǎng)以及在指定的列前沒(méi)有空格或制表符時(shí)的情況。練習(xí)1-23編寫(xiě)ー個(gè)刪除C語(yǔ)言程序中所有的注釋語(yǔ)句。要正確處理帶引號(hào)的字符串與字符常量。在C語(yǔ)言中,注釋不允許嵌套。練習(xí)1-24編寫(xiě)ー個(gè)程序,查找C語(yǔ)言程序中的基本語(yǔ)法錯(cuò)誤,如圓括號(hào)、方括號(hào)、花括號(hào)不配對(duì)等。要正確處理引號(hào)(包括單引號(hào)和雙引號(hào))、傳義字符序列與注釋。(如果讀者想把該程序編寫(xiě)成完全通用的程序,難度會(huì)比較大。)第2章類型、運(yùn)算符與表達(dá)式變曷和常量是程序處理的兩種基本數(shù)據(jù)對(duì)象。聲明語(yǔ)句說(shuō)明變量的名字及類型,也可以指定變量的初值。運(yùn)算符指定將要進(jìn)行的操作。表達(dá)式則把變量與常量組合起來(lái)生成新的值。對(duì)象的類型決定該對(duì)象可取值的集合以及可以對(duì)該對(duì)象執(zhí)行的操作。本章將詳細(xì)講述這些內(nèi)容。ANSI標(biāo)準(zhǔn)對(duì)語(yǔ)言的基本類型與表達(dá)式做了許多小的修改與增補(bǔ)。所有整型都包括signed(帶符號(hào))和unsigned(無(wú)符號(hào))兩種形式,且可以表不無(wú)符號(hào)常量與十六進(jìn)制字符常量。浮點(diǎn)運(yùn)算可以以單精度進(jìn)行,還可以使用更高精度的longdouble類型運(yùn)算。字符串常量可以在編譯時(shí)連接。ANSIC還支持枚舉類型,該語(yǔ)言特性經(jīng)過(guò)了長(zhǎng)期的發(fā)展オ形成。對(duì)象可以聲明為const(常量)類型,表明其值不能修改。該標(biāo)準(zhǔn)還對(duì)算術(shù)類型之間的自動(dòng)強(qiáng)制轉(zhuǎn)換規(guī)則進(jìn)行了擴(kuò)充,以適合于更多的數(shù)據(jù)類型。變量名對(duì)變量的命名與符號(hào)常量的命名存在ー些限制條件,這一點(diǎn)我們?cè)诘?章沒(méi)有說(shuō)明。名字是由字母和數(shù)字組成的序列,但其第一個(gè)字符必須為字母。下劃線“一”被看做是字母,通常用于命名較長(zhǎng)的變量名,以提髙其可讀性。由于例程的名字通常以f劃線開(kāi)頭,因此變量名不要以下劃線開(kāi)頭。大寫(xiě)字母與小寫(xiě)字母是有區(qū)別的,所以,x與X是兩個(gè)不同的名字。在傳統(tǒng)的C語(yǔ)言用法中,變量名使用小寫(xiě)字母,符號(hào)常量名全部使用大寫(xiě)字母。對(duì)于內(nèi)部名而言,至少前31個(gè)字符是有效的。函數(shù)名與外部變量名包含的字符數(shù)目可能小于31,這是因?yàn)閰R編程序和加載程序可能會(huì)使用這些外部名,而語(yǔ)言本身是無(wú)法控制加載和匯編程序的。對(duì)于外部名,ANSI標(biāo)準(zhǔn)僅保證前6個(gè)字符的惟一性,并且不區(qū)分大小寫(xiě)。類似于if、else、int、float等關(guān)鍵字是保留給語(yǔ)言本身使用的,不能把它們用做變量名。所有關(guān)健字中的字符都必須小寫(xiě)。選擇的變量名要能夠盡量從字面上表達(dá)變量的用途,這樣做不容易引起混淆。局部變量一般使用較短的變量名(尤其是循環(huán)控制變量),外部變量使用較長(zhǎng)的名字。數(shù)據(jù)類型及長(zhǎng)度C語(yǔ)言只提供了下列幾種基本數(shù)據(jù)類型:char 字符型,占用ー個(gè)字節(jié),可以存放本地字符集中的ー個(gè)字符int 整型,通常反映了所用機(jī)器中整數(shù)的最自然長(zhǎng)度f(wàn)loat單精度浮點(diǎn)型double雙精度浮點(diǎn)型此外,還可以在這些基本數(shù)據(jù)類型的前面加上一些限定符。short與long兩個(gè)限定符用于限定整型,shortintsh;longintcounter;在上述這種類型的聲明中,關(guān)鍵字int可以省略。通常很多人也習(xí)慣這么做。short與long兩個(gè)限定符的引入可以為我們提供滿足實(shí)際需要的不同長(zhǎng)度的整型數(shù)。1nt通常代表特定機(jī)器中整數(shù)的自然長(zhǎng)度。short類型通常為16位,long類型通常為32位,int類型可以為16位或32位。各編譯器可以根據(jù)硬件特性自主選擇合適的類型長(zhǎng)度,但要遵循下列限制:short與int類型至少為16位,而long類型至少為32位,并且short類型不得長(zhǎng)于int類型,而int類型不得長(zhǎng)于!ong類型。類型限定符signed與unsigned可用于限定char類型或任何整型。unsigned類型的數(shù)總是正值或。,并遵守算術(shù)模2”定律,其中n是該類型占用的位數(shù)。例如,如果char對(duì)象占用8位,那么unsignedchar類型變量的取值范圍為〇?255,而signedchar類型變量的取值范圍則為T(mén)28~127(在采用對(duì)二的補(bǔ)碼的機(jī)器上)。不帶限定符的char類型對(duì)象是否帶符號(hào)則取決于具體機(jī)器,但可打印字符總是正值。longdouble類型表示高精度的浮點(diǎn)數(shù)。同整型ー樣,浮點(diǎn)型的長(zhǎng)度也取決于具體的實(shí)現(xiàn)。門(mén)oat、double與longdouble類型可以表不相同的長(zhǎng)度,也可以表不兩種或三種不同的長(zhǎng)度。冇關(guān)這些類型長(zhǎng)度定義的符號(hào)常量以及其它與機(jī)器和編譯器有關(guān)的屬性可以在標(biāo)準(zhǔn)頭文件(limits. .匕〉中找到,這些內(nèi)

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論