C語(yǔ)言程序設(shè)計(jì) 課件 梁偉 第9、10章 編譯預(yù)處理、文件_第1頁(yè)
C語(yǔ)言程序設(shè)計(jì) 課件 梁偉 第9、10章 編譯預(yù)處理、文件_第2頁(yè)
C語(yǔ)言程序設(shè)計(jì) 課件 梁偉 第9、10章 編譯預(yù)處理、文件_第3頁(yè)
C語(yǔ)言程序設(shè)計(jì) 課件 梁偉 第9、10章 編譯預(yù)處理、文件_第4頁(yè)
C語(yǔ)言程序設(shè)計(jì) 課件 梁偉 第9、10章 編譯預(yù)處理、文件_第5頁(yè)
已閱讀5頁(yè),還剩87頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

第9章編譯預(yù)處理9.1文件包含9.2宏定義9.3條件編譯9.4預(yù)處理命令的綜合示例本章小結(jié)

9.1文件包含

9.1.1文件包含命令的作用如果文件A中有一條文件包含預(yù)處理命令,如:#include<B>則該命令將指定文件B的內(nèi)容復(fù)制到文件A中“#include<B>”命令處的位置,共同組成一個(gè)程序文件,即在文件A中產(chǎn)生文件B的一個(gè)副本。

例如:

圖9-1所示是一個(gè)文件包含關(guān)系的示意圖。文件file1.c中的包含命令“#include"file2.c"”將文件file2.c復(fù)制進(jìn)文件file1.c中。圖(a)和圖(b)所示是預(yù)處理前的情況,圖(c)是將文件file2.c復(fù)制文件file1.c之后的file1.c結(jié)構(gòu)示意圖。圖9-1文件包含關(guān)系的示意圖

9.1.2#include命令的兩種格式

#include命令有兩種格式:

格式一:#include<文件名>

格式二:#include"文件名"

兩種格式的區(qū)別是:用尖括號(hào)時(shí),系統(tǒng)到存放C語(yǔ)言庫(kù)函數(shù)頭文件所在的目錄(一般是C編譯系統(tǒng)的include子目錄)中尋找要復(fù)制的文件(這稱(chēng)為標(biāo)準(zhǔn)方式)。用雙引號(hào)時(shí),系統(tǒng)先在用戶(hù)當(dāng)前目錄中或指定目錄中尋找要復(fù)制的文件,若找不到,再按標(biāo)準(zhǔn)方式查找(即按尖括號(hào)的方式查找)。

通常,如果為調(diào)用系統(tǒng)庫(kù)函數(shù)而用“#include”命令來(lái)復(fù)制相應(yīng)的頭文件(如stdio.h、math.h、string.h等),宜采用尖括號(hào),以節(jié)省查找時(shí)間。如果要復(fù)制的文件是用戶(hù)自己定義的(這種文件一般都位于當(dāng)前目錄下),宜采用雙引號(hào)。

在程序設(shè)計(jì)中,文件包含是很有用的。一個(gè)大的程序可以分為多個(gè)模塊,由多個(gè)程序員分別編程。有些公用的符號(hào)常量或宏定義等可單獨(dú)組成一個(gè)文件,在其他文件的開(kāi)頭用復(fù)制命令包含該文件即可使用。這樣,可避免在每個(gè)文件開(kāi)頭都去書(shū)寫(xiě)那些公用的量,從而節(jié)省時(shí)間,并減少出錯(cuò)。

例9-1設(shè)計(jì)一個(gè)求n!的函數(shù),存放于文件exam.c中,然后設(shè)計(jì)主函數(shù)文件file.c,計(jì)算p=n!/m!/(n-m)!。

9.2宏定義

宏定義有兩種,即不帶參數(shù)的宏和帶參數(shù)的宏。宏定義的作用是用標(biāo)識(shí)符來(lái)代表一字符串,一旦對(duì)字符串命名,就可在源程序中使用宏定義標(biāo)識(shí)符,系統(tǒng)編譯之前會(huì)自動(dòng)查找標(biāo)識(shí)符并替換成字符串。

9.2.1不帶參數(shù)的宏

不帶參數(shù)的宏定義的一般形式為

#define宏名宏體

其中:“#”表示這是一條預(yù)處理命令;“define”為宏定義命令;“宏名”為一個(gè)合法的標(biāo)識(shí)符,一般建議用大寫(xiě)字母,以與變量名相區(qū)別;“宏體”可以是常數(shù)、表達(dá)式或語(yǔ)句,甚至可以是多條語(yǔ)句。define、宏名、宏體三者之間要用一個(gè)或多個(gè)空格分隔。

例如:

#definePI3.1415926

在預(yù)處理時(shí),系統(tǒng)在該宏定義以后查找出現(xiàn)的每一個(gè)宏名都用宏體來(lái)代替,這個(gè)過(guò)程叫宏替換。

例9-2求球的表面積和體積。

在預(yù)處理時(shí),系統(tǒng)會(huì)查找main()函數(shù)中的宏P(guān)I并用宏體3.141?592?6替換。預(yù)編譯后文件將變?yōu)?/p>

例9-3使用無(wú)參宏定義格式控制輸出。

程序運(yùn)行結(jié)果為

Wangyi1308001621.00

Liwei1308002612.00

采用宏定義后,如果要修改PI值,只需在宏定義處修改PI值,而不需在計(jì)算面積和體積等多處修改,減少了代碼修改量,降低了程序出錯(cuò)的可能性,提高了程序的健壯性。

9.2.2帶參數(shù)的宏

帶參數(shù)宏定義的一般形式為

#define宏名(參數(shù))宏體

例如

#defineSQR(x)(x)*(x)

#defineMOD(x,y)(x)%(y)

預(yù)處理時(shí),系統(tǒng)在用宏體代替宏名的同時(shí),實(shí)在參數(shù)會(huì)代替宏體中形式參數(shù),同樣宏替換仍只是一種簡(jiǎn)單的查找替換,不能進(jìn)行計(jì)算或?qū)崿F(xiàn)其他的功能。

當(dāng)程序出現(xiàn)下列語(yǔ)句時(shí):

y=SQR(a+b);

程序在預(yù)處理時(shí),將被替換成如下語(yǔ)句:

y=(a+b)*(a+b);

例9-4帶參宏定義示例。

帶參數(shù)的宏定義可以嵌套調(diào)用其他已存在的宏,即下一個(gè)宏定義的宏體可以出現(xiàn)上面已經(jīng)定義過(guò)的宏名。

例如:

#defineSQR(x)(x)*(x)

#defineCUBE(x)SQR(x)*(x)

語(yǔ)句CUBE(a+b)進(jìn)行宏展開(kāi)后,變?yōu)?/p>

(a+b)*(a+b)*(a+b)

例9-5比較宏定義中括號(hào)的使用方法的示例。

程序運(yùn)行結(jié)果為

輸入一個(gè)數(shù):3

SQ1:sq=16

SQ2:sq=7

SQ3:sq=16

SQ1:sq=160

SQ2:sq=57

SQ3:sq=10

在宏替換中,不管有無(wú)參數(shù),宏名總是原封不動(dòng)替換成定義串,當(dāng)定義串中帶有括號(hào)時(shí),替換時(shí)這些括號(hào)原樣出現(xiàn)在替換結(jié)果中,即宏定義串中的括號(hào)不是運(yùn)算符,僅表示括號(hào)符號(hào)。對(duì)于SQ2、SQ3的宏來(lái)說(shuō),若替換方式為

sq=160/SQ2(a+1);sq=160/SQ3(a+1);

即將參數(shù)a+1分別傳入宏SQ2和SQ3中,有無(wú)括號(hào)的替換對(duì)結(jié)果的影響很大。SQ2被替換成“160/a+1*a+1”;而SQ3替換后可表示為“160/((a+1)*(a+1))”。

9.3條件編譯

C語(yǔ)言提供了條件編譯的預(yù)處理命令,可以按不同的條件去編譯不同的程序部分,進(jìn)而產(chǎn)生不同的目標(biāo)代碼文件。一般情況下,源程序的所有語(yǔ)句都會(huì)參加編譯。但有時(shí)若希望只對(duì)其中的部分滿(mǎn)足條件的語(yǔ)句進(jìn)行編譯,則要用到“條件編譯”。條件編譯是在對(duì)源程序編譯之前的處理中,根據(jù)給定的條件,決定只編譯其中的某一部分源程序,而不編譯另外一部分源程序(塊刪除)。條件編譯有3種格式。

1.格式一

條件編譯格式一的一般形式為

#ifdef標(biāo)識(shí)符

程序段1

#else

程序段2

#endif

條件編譯格式的功能:如果標(biāo)識(shí)符已經(jīng)被“#define”命令定義過(guò),則當(dāng)程序編譯時(shí)只對(duì)程序段1進(jìn)行編譯,否則只對(duì)程序段2進(jìn)行編譯。其中的程序段可以是一條語(yǔ)句,也可以是一組語(yǔ)句。如果是一組語(yǔ)句,不必像復(fù)合語(yǔ)句一樣加上花括號(hào)。

例9-6條件編譯格式一的示例。

例9-7條件編譯#if-#else-#endif的用法示例。

程序運(yùn)行結(jié)果為

選用較小的值編譯.

程序的編譯過(guò)程取決于MAX定義的大小,當(dāng)MAX>99時(shí),使用#if部分編譯,而#else部分是不進(jìn)行編譯的,反之亦然。

在程序的第1行宏定義中,定義MAX表示常量10,在本例中表示一個(gè)數(shù)值。若條件判斷為非0的數(shù)表示真,否則為假。MAX也可以為任何字符串,可以根據(jù)需要自行定義符號(hào)常量,只要定義了,就編譯滿(mǎn)足條件的部分。

2.格式二

條件編譯格式二的一般形式為

#ifndef標(biāo)識(shí)符

程序段1

#else

程序段2

#endif

格式二與格式一的不同之處是將“ifdef”改成“ifndef”。其功能是:如果標(biāo)識(shí)符沒(méi)有被“#define”命令定義過(guò),則當(dāng)程序編譯時(shí)只對(duì)程序段1進(jìn)行編譯,否則只對(duì)程序段2進(jìn)行編譯。這與格式一的功能恰好相反。

例9-8利用條件編譯,計(jì)算面積。

3.格式三

條件編譯格式三的一般形式為

#if常量表達(dá)式

程序段1

#else

程序段2

#endif

條件編譯格式三的功能:如果常量表達(dá)式的值為真(即非0),則當(dāng)程序編譯時(shí)只對(duì)程序段1進(jìn)行編譯,否則只對(duì)程序段2進(jìn)行編譯。

例9-9條件編譯格式三的示例。

條件編譯當(dāng)然也可用條件語(yǔ)句(if語(yǔ)句)來(lái)實(shí)現(xiàn),但若用條件語(yǔ)句將會(huì)對(duì)整個(gè)源程序進(jìn)行編譯,造成目標(biāo)程序長(zhǎng),可執(zhí)行程序的運(yùn)行時(shí)間長(zhǎng);而采用條件編譯,可減少被編譯的語(yǔ)句,從而減少了目標(biāo)程序的長(zhǎng)度和可執(zhí)行程序的運(yùn)行時(shí)間(少了關(guān)系運(yùn)算并跳轉(zhuǎn)的時(shí)間)。

9.4預(yù)處理命令的綜合示例

例9-10用條件編譯輸入一行電報(bào)文字,破解電報(bào)的密碼是每個(gè)字母都會(huì)被輸出到字母表對(duì)應(yīng)的下一個(gè)字母。

例9-11三角形面積公式為

,其中S?=?(a?+?b?+?c?)/2,a、b、c為三角形的三邊。定義兩個(gè)帶參的宏,一個(gè)用來(lái)求面積,另一個(gè)宏用來(lái)求S。

本章小結(jié)

本章主要介紹了文件包含、宏定義和條件編譯等三種編譯預(yù)處理類(lèi)型。首先介紹了文件包含命令和#include命令的形式等;然后介紹了宏定義,即不帶參數(shù)的宏與帶參數(shù)的宏,以提高代碼可讀性和可維護(hù)性;最后介紹了條件編譯,可允許開(kāi)發(fā)者根據(jù)需要選擇編譯過(guò)程,管理不同的代碼路徑,以保持代碼庫(kù)的簡(jiǎn)潔和可維護(hù)性。第10章文件10.1文件概述和文件類(lèi)型指針10.2文件的打開(kāi)和關(guān)閉10.3文件的讀/寫(xiě)10.4文件的定位10.5文件的檢測(cè)10.6文件的綜合示例本章小結(jié)

10.1文件概述和文件類(lèi)型指針

10.1.1文件概述文件(file)是程序設(shè)計(jì)中一個(gè)重要的概念。在計(jì)算機(jī)系統(tǒng)中,“文件”是指存儲(chǔ)在外部介質(zhì)上的一組相關(guān)數(shù)據(jù)的有序集合。在前面章節(jié)中,我們采用標(biāo)準(zhǔn)輸入(鍵盤(pán)輸入)和標(biāo)準(zhǔn)輸出(顯示器輸出)模式來(lái)處理數(shù)據(jù)信息。但大型程序常把外部介質(zhì)(如磁盤(pán))作為信息載體,用于長(zhǎng)期存儲(chǔ)輸入和輸出數(shù)據(jù)。

文件系統(tǒng)中,C語(yǔ)言將輸入/輸出設(shè)備當(dāng)作文件,將輸入/輸出文件作為輸入/輸出流對(duì)象進(jìn)行處理。輸入/輸出是數(shù)據(jù)“流動(dòng)”的過(guò)程。當(dāng)輸入操作時(shí),系統(tǒng)利用“讀操作”使數(shù)據(jù)從文件流向計(jì)算機(jī)內(nèi)存;當(dāng)輸出操作時(shí),系統(tǒng)利用“寫(xiě)操作”使數(shù)據(jù)從計(jì)算機(jī)流向文件(如磁盤(pán)、打印機(jī)等)。

文件可以從不同的角度來(lái)進(jìn)行分類(lèi):

(1)按文件所依附的介質(zhì)分類(lèi),有卡片文件、紙帶文件、磁帶文件和磁盤(pán)文件等。

(2)按文件內(nèi)容分類(lèi),有源文件、目標(biāo)程序文件和數(shù)據(jù)文件等。

(3)按文件操作分類(lèi),有輸入文件、輸出文件和輸入/輸出文件。

(4)按文件中的數(shù)據(jù)組織形式分類(lèi),有字符文件和二進(jìn)制文件。

字符文件又稱(chēng)為ASCII文件或文本文件,按字符方式存儲(chǔ),可用文本編輯器(如Windows系統(tǒng)中的記事本notepad.exe、寫(xiě)字板wordpad.exe等)進(jìn)行直接讀寫(xiě),但所占存儲(chǔ)空間較大;二進(jìn)制文件是以二進(jìn)制方式存儲(chǔ)的,所占存儲(chǔ)空間小,用文本編輯器不便進(jìn)行直接讀寫(xiě)。圖10-1顯示了十進(jìn)制整數(shù)12345以字符文件存儲(chǔ)和以二進(jìn)制文件存儲(chǔ)的區(qū)別。在C語(yǔ)言系統(tǒng)中,一個(gè)文件就是一個(gè)字符(字節(jié))流。圖10-1字符文件和二進(jìn)制文件的存儲(chǔ)區(qū)別

C語(yǔ)言文件系統(tǒng)有兩種:緩沖文件系統(tǒng)(標(biāo)準(zhǔn)I/O)和非緩沖文件系統(tǒng)(系統(tǒng)I/O)。緩沖文件系統(tǒng)的特點(diǎn)是:系統(tǒng)在內(nèi)存為正在使用的每一個(gè)文件開(kāi)辟一個(gè)固定容量的“緩沖區(qū)”,當(dāng)執(zhí)行讀操作時(shí),先從磁盤(pán)上將指定的文件數(shù)據(jù)寫(xiě)入緩沖區(qū),待緩沖區(qū)裝滿(mǎn)后再?gòu)木彌_區(qū)逐個(gè)將數(shù)據(jù)送到程序數(shù)據(jù)區(qū);當(dāng)執(zhí)行寫(xiě)操作時(shí),先將程序數(shù)據(jù)寫(xiě)入緩沖區(qū),待緩沖區(qū)裝滿(mǎn)后再送到磁盤(pán),如圖10-2所示。

圖10-2標(biāo)準(zhǔn)I/O讀寫(xiě)文件操作示意圖

由此可以看出,緩沖區(qū)越大,對(duì)外設(shè)訪(fǎng)問(wèn)的次數(shù)就越少,執(zhí)行速度就越快、效率越高。一般來(lái)說(shuō),文件緩沖區(qū)的大小與編程環(huán)境有關(guān),一般為512B。非緩沖文件,系統(tǒng)的特點(diǎn)是系統(tǒng)不會(huì)自動(dòng)為正在使用的每一個(gè)文件開(kāi)辟緩沖區(qū),而由程序根據(jù)自身的需要及系統(tǒng)的存儲(chǔ)資源情況來(lái)為每一個(gè)文件設(shè)定緩沖區(qū)。目前仍有許多C版本支持非緩沖文件系統(tǒng),但1983年ANSIC標(biāo)準(zhǔn)決定不采用非緩沖區(qū)文件系統(tǒng),因此這里建議讀者不要采用不符合ANSIC標(biāo)準(zhǔn)的那些部分,以免降低程序的可移植性。

10.1.2文件類(lèi)型指針

文件類(lèi)型指針是緩沖文件系統(tǒng)中最重要的概念。對(duì)緩沖文件系統(tǒng)來(lái)說(shuō),ANSIC在內(nèi)存中為每個(gè)被使用的文件開(kāi)辟一小塊固定大小的區(qū)域,用于存放文件的屬性狀態(tài)(如文件名、緩沖區(qū)的位置與大小等信息),該區(qū)域利用一個(gè)結(jié)構(gòu)類(lèi)型變量存放。該變量的結(jié)構(gòu)類(lèi)型是由系統(tǒng)定義的,取名為FILE,其定義包含在頭文件stdio.h中,格式如下:

在C語(yǔ)言中,允許用類(lèi)型FILE定義文件指針。每當(dāng)要對(duì)某個(gè)文件進(jìn)行操作時(shí),應(yīng)先定義一個(gè)FILE類(lèi)型文件指針指向該文件,然后通過(guò)該文件指針對(duì)文件進(jìn)行操作。文件指針的定義格式為

FILE*文件指針名;

例如:

FILE*fp;

定義了一個(gè)FILE類(lèi)型的文件指針,指針名為fp。

10.2文件的打開(kāi)和關(guān)閉

10.2.1文件的打開(kāi)和其他高級(jí)語(yǔ)言一樣,對(duì)文件進(jìn)行讀/寫(xiě)操作之前需要先“打開(kāi)”該文件。所謂“打開(kāi)”,是指為文件建立相應(yīng)的信息區(qū)(用來(lái)存放文件的相關(guān)信息)和文件緩沖區(qū),并建立文件與它們之間的聯(lián)系。C語(yǔ)言提供了打開(kāi)文件的函數(shù)fopen()。該函數(shù)原型在stdio.h頭文件中,其調(diào)用格式為FILE*fp;fp=fopen("文件名","文件操作模式");

或者將上述兩句合并為下面一句:

FILE*fp=fopen("文件名","文件操作模式");

其功能是打開(kāi)一個(gè)由“文件名”指向的外部文件,返回值是一個(gè)指向該文件的文件指針。在文件名中可以指明存儲(chǔ)盤(pán)及文件路徑。若文件打開(kāi)成功,則fp為一非空指針,否則fp值為NULL。表10-1是“文件操作模式”的類(lèi)別及含義。.

例如:

FILE*fp;

fp=fopen("d:\\class.txt","r");

其功能是以只讀方式在D盤(pán)根目錄下打開(kāi)名為“class.txt”的文本文件,允許進(jìn)行讀操作,并使fp指向該文件。C語(yǔ)言中,兩個(gè)反斜線(xiàn)“\\”屬于轉(zhuǎn)義字符,代表反斜杠字符“\”。

又如:

FILE*fp;

fp=fopen("c:\\class.txt","rb");

其功能是打開(kāi)C盤(pán)根目錄下的文件“class.txt”,只允許按二進(jìn)制方式進(jìn)行讀操作。

對(duì)于文件操作模式,有以下幾點(diǎn)說(shuō)明:

(1)凡用“r”打開(kāi)一個(gè)文件時(shí),該文件必須已經(jīng)存在,且只能從該文件讀取數(shù)據(jù)。

(2)凡用“w”打開(kāi)的文件,只能向該文件寫(xiě)入。若打開(kāi)的文件不存在,則以指定的文件名建立該文件。若打開(kāi)的文件已經(jīng)存在,則將該文件刪去,以指定的文件名重建一個(gè)新文件。

(3)若要向一個(gè)已存在的文件追加新的信息,只能用追加(“a”)方式打開(kāi)文件。但此時(shí)該文件必須是存在的,否則將會(huì)出錯(cuò)。

(4)在打開(kāi)一個(gè)文件時(shí),如果出錯(cuò),fopen()將返回一個(gè)空指針值NULL。在程序中可以用這一信息來(lái)判別是否完成打開(kāi)文件的工作,并進(jìn)行相應(yīng)的處理。

(5)把一個(gè)文本文件讀入內(nèi)存時(shí),系統(tǒng)將ASCII碼轉(zhuǎn)換成二進(jìn)制碼,而把文件以文本方式寫(xiě)入磁盤(pán)時(shí),系統(tǒng)要把二進(jìn)制碼轉(zhuǎn)換成ASCII碼,因此文本文件的讀寫(xiě)要花費(fèi)較多的轉(zhuǎn)換時(shí)間。對(duì)二進(jìn)制文件的讀寫(xiě)不存在這種轉(zhuǎn)換。

(6)標(biāo)準(zhǔn)輸入文件(鍵盤(pán))、標(biāo)準(zhǔn)輸出文件(顯示器)和標(biāo)準(zhǔn)出錯(cuò)輸出文件(顯示器)是在程序運(yùn)行時(shí)由系統(tǒng)自動(dòng)打開(kāi)的,可直接使用而無(wú)須打開(kāi)與它們相連的終端文件。

例10-1在指定路徑下打開(kāi)一個(gè)文件。

上述程序的功能是:如果返回的指針為空,表示不能打開(kāi)D盤(pán)根目錄下的“class.txt”文件,則給出提示信息“cannotopenfile!”。程序中的exit(0)表示終止程序執(zhí)行并返回值0,其在main()函數(shù)中的作用相當(dāng)于return0。

10.2.2文件的關(guān)閉

文件一旦使用完畢,要用關(guān)閉文件函數(shù)把文件關(guān)閉,以免出現(xiàn)文件數(shù)據(jù)丟失等錯(cuò)誤。所謂“關(guān)閉文件”,就是使文件指針變量不再指向該文件,即讓文件指針變量與被關(guān)閉的文件“脫鉤”。關(guān)閉文件還可將未滿(mǎn)的輸出緩沖區(qū)數(shù)據(jù)寫(xiě)入文件,將未滿(mǎn)的輸入緩沖區(qū)數(shù)據(jù)取出,以免數(shù)據(jù)丟失,同時(shí)撤銷(xiāo)文件信息區(qū)和緩沖區(qū),斷開(kāi)文件與內(nèi)存的聯(lián)系。C語(yǔ)言提供了關(guān)閉文件的fclose()函數(shù),該函數(shù)原型也在stdio.h頭文件中,其調(diào)用格式為

fclose(文件指針);

若關(guān)閉文件操作成功,則fclose()函數(shù)返回值為0,否則返回EOF(-1)。

例10-2以只讀方式打開(kāi)和關(guān)閉一個(gè)名為class.txt的二進(jìn)制文件\n。

10.3文件的讀/寫(xiě)

當(dāng)文件按指定的工作方式打開(kāi)以后,就可以對(duì)文件進(jìn)行讀和寫(xiě)操作了。對(duì)文本文件來(lái)說(shuō),可按字符讀寫(xiě)或按字符串讀寫(xiě);對(duì)二進(jìn)制文件來(lái)說(shuō),可進(jìn)行成塊的讀寫(xiě)或格式化的讀寫(xiě)。C語(yǔ)言提供了多種文件讀/寫(xiě)函數(shù),如表10-2所示,這些函數(shù)原型都在stdio.h頭文件中。

10.3.1字符讀/寫(xiě)函數(shù)

fgetc()和fputc()函數(shù)分別用于對(duì)文本文件進(jìn)行單個(gè)字符的讀和寫(xiě)。其調(diào)用格式分別為

ch=fgetc(fp); /*fp為文件指針*/

fgetc(fp)函數(shù)從文件指針?biāo)赶蛭募漠?dāng)前位置返回一個(gè)字符,并將文件指針指示器移到下一個(gè)字符位置。如果文件指示器已到文件末尾,則函數(shù)返回一個(gè)EOF(EOF是一個(gè)符號(hào)常量,值為-1,定義在stdio.h頭文件中),表示讀入的不是正常的字符而是文件結(jié)束符。

fputc(ch,fp)函數(shù)將字符ch的值寫(xiě)入fp所指向文件的當(dāng)前位置(文件內(nèi)部指針指向)處,并將文件內(nèi)部指針后移一位。fputc()函數(shù)的返回值是所寫(xiě)入字符的值,出錯(cuò)時(shí)返回EOF。讀/寫(xiě)文件操作完成后,應(yīng)關(guān)閉相應(yīng)文件。

例10-3從鍵盤(pán)多次輸入單個(gè)字符,存到磁盤(pán)文件class.txt中,當(dāng)輸入“#”時(shí)結(jié)束。

例10-4先將存放于磁盤(pán)的指定文本文件的內(nèi)容按只讀方式讀取,再將其顯示到屏幕上。要求采用帶參數(shù)的main(),指定的磁盤(pán)文件名由命令行方式通過(guò)鍵盤(pán)輸入。

對(duì)于fgetc()和fputc()函數(shù)的使用,有以下幾點(diǎn)說(shuō)明:

(1)在fgetc()函數(shù)調(diào)用中,讀取的文件必須是以只讀或讀/寫(xiě)方式打開(kāi)的;而在fputc()函數(shù)調(diào)用中,被寫(xiě)入的文件可用只寫(xiě)、讀/寫(xiě)和追加方式打開(kāi)。

(2)讀取字符的結(jié)果也可用字符變量保存,例如,ch=fgetc(fp)。

(3)在文件內(nèi)部用位置指針來(lái)指向文件的當(dāng)前讀/寫(xiě)位置,每讀/寫(xiě)一次,該指針均向后移動(dòng)。在文件打開(kāi)時(shí),該指針由系統(tǒng)自動(dòng)設(shè)置,并總是指向文件的首字節(jié)。

(4)在fputc()函數(shù)調(diào)用中,用只寫(xiě)方式打開(kāi)一個(gè)文件時(shí),如果原來(lái)不存在該文件,則在打開(kāi)時(shí)新建立一個(gè)以指定名字命名的文件;如果原來(lái)已存在一個(gè)以該文件名命名的文件,則在打開(kāi)時(shí)將該文件刪去,然后重新建立一個(gè)新文件。

10.3.2字符串讀/寫(xiě)函數(shù)

C語(yǔ)言提供的fgets()和fputs()函數(shù)分別用于實(shí)現(xiàn)對(duì)文本文件的字符串讀和寫(xiě)操作。這兩個(gè)函數(shù)的調(diào)用格式分別為

fgets(字符數(shù)組,n,fp);

fputs(字符串,fp);

fgets(字符數(shù)組,n,fp)從指定的文件中將長(zhǎng)度n-1的字符串讀到字符數(shù)組中,在最后一個(gè)讀取的字符后加結(jié)束符?'\0'。若在讀取n-1個(gè)字符之前遇到了換行符或EOF,則讀操作結(jié)束。若讀取數(shù)據(jù)成功,函數(shù)fgets()則返回字符數(shù)組的首地址,否則返回NULL。字符數(shù)組名也可以由字符指針變量代替,本質(zhì)上都是將讀取的字符串存放在相應(yīng)的存儲(chǔ)區(qū)中。

fputs(字符串,fp)向指定文件寫(xiě)入一個(gè)字符串,其中字符串可以是字符串常量、字符數(shù)組名或字符型指針變量。字符串結(jié)束符'\0'不寫(xiě)入。若寫(xiě)入成功,則函數(shù)值為0;若寫(xiě)入失敗,則返回為EOF。

fgets()和fputs()函數(shù)與gets()和puts()函數(shù)類(lèi)似,只是gets()和puts()函數(shù)以終端為操作對(duì)象,而fgets()和fputs()函數(shù)以指定的文本文件為操作對(duì)象。

例10-5從test.txt文件中讀取字符串,再寫(xiě)入例10-3的class.txt文件,并顯示后者的內(nèi)容。

本例中要對(duì)兩個(gè)文件進(jìn)行操作,需定義兩個(gè)文件變量指針。在操作文件以前,應(yīng)將兩個(gè)文件以不同的工作方式打開(kāi)(不分先后),讀/寫(xiě)完成后再關(guān)閉文件。程序?qū)懭胛募耐瑫r(shí)在屏幕上顯示,故程序運(yùn)行結(jié)束后,在屏幕上可看到目標(biāo)文件class.txt的內(nèi)容。

例10-6從例10-5的class.txt文件中讀入長(zhǎng)度為15個(gè)字符的字符串并顯示。

該程序先定義一個(gè)16字節(jié)的字符數(shù)組string,且以只讀方式打開(kāi)文本文件class.txt,讀取15個(gè)字符并送入string數(shù)組(在數(shù)組最后一個(gè)單元內(nèi)將加上?'\0'),然后在屏幕上顯示string數(shù)組。

例10-7向例10-6中的class.txt文件末尾追加一個(gè)字符串,并顯示文件內(nèi)容。

10.3.3格式化讀/寫(xiě)函數(shù)

C語(yǔ)言提供了對(duì)磁盤(pán)文件進(jìn)行格式化讀/寫(xiě)的函數(shù)fscanf()和fprintf()。這兩個(gè)函數(shù)的調(diào)用格式分別為

scanf(文件指針,格式字符串,輸入列表);

fprintf(文件指針,格式字符串,輸出列表);

fscanf()函數(shù)按指定的格式從“文件指針”指向的磁盤(pán)文件上將數(shù)據(jù)讀取并存儲(chǔ)至“輸入列表”指定的數(shù)據(jù)緩存區(qū)中。

fprintf()函數(shù)將“輸出列表”數(shù)據(jù)按指定的格式輸出到“文件指針”指向的磁盤(pán)文件上。

由于C語(yǔ)言引入了這兩個(gè)格式化輸入/輸出函數(shù),因此文件在存儲(chǔ)格式上滿(mǎn)足某種指定格式。例如:

fscanf(fp,"%d%s",&a,str); /*a為整型普通變量,str為字符指針變量或字符數(shù)組名*/

fprintf(fp,"%d%s",a,str);

例10-8先將兩個(gè)學(xué)生記錄,包括姓名、學(xué)號(hào)、兩科成績(jī)的數(shù)據(jù),以格式化的數(shù)據(jù)格式寫(xiě)入文本文件grades.txt中,再?gòu)脑撐募幸愿袷交椒ㄗx出并顯示到屏幕上。

10.3.4數(shù)據(jù)塊讀/寫(xiě)函數(shù)

前面介紹的幾種讀/寫(xiě)文件的方法,對(duì)于復(fù)雜的數(shù)據(jù)類(lèi)型無(wú)法以整體形式向文件寫(xiě)入或從文件讀出。為了解決這個(gè)問(wèn)題,C語(yǔ)言提供成塊的讀/寫(xiě)方式來(lái)操作文件,使數(shù)組或結(jié)構(gòu)體等類(lèi)型可以進(jìn)行一次性讀/寫(xiě)。

C語(yǔ)言提供的數(shù)據(jù)塊讀/寫(xiě)函數(shù)fread()和fwrite(),可用來(lái)讀/寫(xiě)一組數(shù)據(jù)(一個(gè)數(shù)據(jù)塊)。數(shù)據(jù)塊讀/寫(xiě)函數(shù)的調(diào)用格式為

fread(buffer,size,n,fp);

fwrite(buffer,size,n,fp);

其中:buffer是一個(gè)緩沖區(qū)指針,在fread()函數(shù)中它表示存放讀取數(shù)據(jù)的首地址,在fwrite()函數(shù)中它表示寫(xiě)入數(shù)據(jù)的首地址;size表示每次讀/寫(xiě)的數(shù)據(jù)項(xiàng)的字節(jié)數(shù);n表示要連續(xù)讀/寫(xiě)的數(shù)據(jù)項(xiàng)個(gè)數(shù);fp表示文件指針。每調(diào)用一次數(shù)據(jù)塊讀/寫(xiě)函數(shù)所傳輸?shù)目傋止?jié)數(shù)等于n×size。

fread()函數(shù)從打開(kāi)的文件fp中讀取n個(gè)數(shù)據(jù)項(xiàng)(每個(gè)數(shù)據(jù)項(xiàng)的長(zhǎng)度為size個(gè)字節(jié)),并放入指定的緩沖區(qū)buffer中,所讀的字節(jié)長(zhǎng)度為n?×?size。函數(shù)調(diào)用成功后,返回實(shí)際讀取的數(shù)據(jù)項(xiàng)個(gè)數(shù);若遇文件結(jié)束或出錯(cuò),則返回0。

fwrite()函數(shù)把buffer所指向的n個(gè)數(shù)據(jù)項(xiàng)(每個(gè)數(shù)據(jù)項(xiàng)的長(zhǎng)度為size個(gè)字節(jié))寫(xiě)入已經(jīng)打開(kāi)的文件fp中。函數(shù)返回值為寫(xiě)到文件中的數(shù)據(jù)項(xiàng)個(gè)數(shù)。

例10-9先從鍵盤(pán)輸入兩個(gè)學(xué)生數(shù)據(jù),并將其寫(xiě)入student.txt文件中,再讀取這兩個(gè)學(xué)生的數(shù)據(jù)使之顯示在屏幕上。

通常,若輸入數(shù)據(jù)的格式較為復(fù)雜,可采取將各種格式的數(shù)據(jù)全部當(dāng)作字符串來(lái)輸入,然后將字符串轉(zhuǎn)換為所需的格式。C語(yǔ)言提供如下格式轉(zhuǎn)換函數(shù)來(lái)實(shí)現(xiàn)這種操作:

intatoi(char*ptr);

floatatof(char*ptr);

longintatol(char*ptr);

它們分別將字符串轉(zhuǎn)換為整型、浮點(diǎn)型和長(zhǎng)整型。在程序中加入這些轉(zhuǎn)換函數(shù)后,在程序運(yùn)行輸入數(shù)據(jù)時(shí),操作者不必記住每種數(shù)據(jù)的類(lèi)型,這增強(qiáng)了程序的易用性。使用這些函數(shù)時(shí)須將其頭文件math.h或stdlib.h寫(xiě)在程序的前面。

例10-10將輸入的不同格式的數(shù)據(jù)當(dāng)作字符串輸入例10-8的文件中,然后將其轉(zhuǎn)換,進(jìn)行文件的成塊讀/寫(xiě)。

10.4文件的定位

C語(yǔ)言提供了rewind()函數(shù)和fseek()函數(shù)來(lái)對(duì)文件內(nèi)部的位置指針進(jìn)行移動(dòng)操作。rewind()函數(shù)把位置指針重新移動(dòng)到文件首位置,該函數(shù)無(wú)返回值;fseek()函數(shù)把位置指針移動(dòng)到某一指定位置。這兩個(gè)函數(shù)的調(diào)用格式為rewind(FILE*fp);fseek(FILE*fp,longoffset,intorigin);

其中:文件指針“fp”指向欲移動(dòng)的文件。fseek()函數(shù)中,位移量“offset”表示移動(dòng)的字節(jié)數(shù)且為“l(fā)ong”型數(shù)據(jù),以便在被打開(kāi)的文件的長(zhǎng)度大于64KB時(shí)不會(huì)出錯(cuò)(即文件內(nèi)部的位置指針的移動(dòng)范圍大于64KB)。當(dāng)用常量表示位移量時(shí),要加后綴“L”(表示是長(zhǎng)整型數(shù))。若位移量為正值,則表示從起始點(diǎn)向文件尾方向移動(dòng);若位移量為負(fù)值,則表示從起始點(diǎn)向文件首方向移動(dòng)。起始點(diǎn)“origin”表示從何處開(kāi)始計(jì)算位移量。規(guī)定的起始點(diǎn)有3種:文件首、當(dāng)前位置和文件尾,其表示方法如表10-3所示。

fseek()函數(shù)若操作成功,則其返回值為0,否則為非0。例如:

fseek(fp,100L,0); /*將位置指針從文件首向文件尾方向移動(dòng)100個(gè)字節(jié)*/

fseek(fp,-10L,1); /*將位置指針從當(dāng)前位置向文件首方向移動(dòng)10個(gè)字節(jié)*/

需要說(shuō)明的是,fseek()函數(shù)一般用于二進(jìn)制文件。在文本文件中由于要進(jìn)行轉(zhuǎn)換而產(chǎn)生誤差,故往往容易出現(xiàn)因計(jì)算誤差導(dǎo)致位置指針指向錯(cuò)誤的問(wèn)題。當(dāng)文件內(nèi)部的位置指針按要求進(jìn)行了移動(dòng)之后,對(duì)文件的隨機(jī)讀/寫(xiě)即可用前面介紹的任一種讀/寫(xiě)函數(shù)進(jìn)行讀/寫(xiě)。常通過(guò)fread()和fwrite()函數(shù)與fseek()函數(shù)配合使用來(lái)對(duì)一個(gè)數(shù)據(jù)塊進(jìn)行讀/寫(xiě)操作。

例10-11從鍵盤(pán)輸入字符串到例10-7的class.txt文

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 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ì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論