版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
8.1結(jié)構(gòu)體的定義與使用
8.1.1
定義結(jié)構(gòu)體類型和結(jié)構(gòu)體變量前文介紹過整型、實型和字符型等基本數(shù)據(jù)類型,它們可以直接用于定義變量。結(jié)構(gòu)體類型是一種構(gòu)造數(shù)據(jù)類型。但是,C語言沒有提供結(jié)構(gòu)體類型,而是提供了結(jié)構(gòu)體類型的定義方法,我們在使用時需要自行定義。定義結(jié)構(gòu)體類型與結(jié)構(gòu)體變量的語法格式:struct結(jié)構(gòu)體名{結(jié)構(gòu)體成員列表}結(jié)構(gòu)體變量列表;下一頁返回8.1結(jié)構(gòu)體的定義與使用
在一般情況下,結(jié)構(gòu)體名、結(jié)構(gòu)體成員列表、結(jié)構(gòu)體變量列表至少應出現(xiàn)兩個。
例如,定義一個描述學生信息的結(jié)構(gòu)體類型與相關變量如下:structstudent{charno[10];charname[20];intmath;inteng;intchin;floatsum;};structstudents1,s2,s[10],?pstu;上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
也可以這樣定義:structstudent{charno[10];charname[20];intmath;inteng;intchin;floatsum;}s1,s2,s[10],?ps;上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
這樣,
“structstudent
{···}”
定義了一個結(jié)構(gòu)體類型,structstudent就是結(jié)構(gòu)體類型名(注意:在表示結(jié)構(gòu)體類型名時,關鍵字struct不能省略,student不是類型名),該結(jié)構(gòu)體類型包含6個成員。在定義結(jié)構(gòu)體類型之后,還需要定義結(jié)構(gòu)體變量才可以存儲數(shù)據(jù)。例如,不能使用int存儲數(shù)據(jù),而是需要先通過語句“inta;”定義變量,然后用變量a存儲數(shù)據(jù)。上述代碼定義了結(jié)構(gòu)體類型structstudent,之后定義了兩個structstudent類型的變量s1、
s2以及結(jié)構(gòu)體數(shù)組s[10]和結(jié)構(gòu)體指針ps,
結(jié)構(gòu)體數(shù)組s[10]定義了10個structstudent類型的數(shù)組元素,結(jié)構(gòu)體指針ps定義了一個指向structstudent類型變量的指針。上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
定義了結(jié)構(gòu)體變量后,系統(tǒng)為每個變量分配一塊連續(xù)的存儲空間,各個成員按定義順序依次存放。例如,在VC60開發(fā)環(huán)境下,student成員no、math、eng、chin是整型,占4字節(jié);成員name是字符型數(shù)組,占20字節(jié);成員sum是實型,占4字節(jié),所以變量s1和s2都占40字節(jié)的存儲空間,s1的存儲空間如圖8-1所示。上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
結(jié)構(gòu)體類型與結(jié)構(gòu)體變量的定義也可以省略結(jié)構(gòu)體名,直接定義結(jié)構(gòu)體類型變量,例如:struct{charno[10];charname[20];intmath;inteng;intchin;floatsum;}s1,s2;上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
可以使用typedef為結(jié)構(gòu)體類型指定一個方便使用的名字。例如:typedefstructstudent{charno[10];charname[20];intmath;inteng;intchin;floatsum;}STU;在這個結(jié)構(gòu)體類型的定義中,typedef為結(jié)構(gòu)體類型structstudent起了一個新的名字STU。上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
注意:這里的STU不是結(jié)構(gòu)體變量,而是structstudent的別名。在隨后的程序中,既可以使用structstudent定義結(jié)構(gòu)體變量,也可以使用STU定義結(jié)構(gòu)體變量。例如:STUs1,s2,s[10],?ps;structstudents3;ps=(STU?)malloc(sizeof(STU));
注意:typedef并不引入一個新的數(shù)據(jù)類型,只是給已定義的數(shù)據(jù)類型指定一個同義詞。上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
8.1.2
初始化結(jié)構(gòu)體變量和其他類型的變量一樣,結(jié)構(gòu)體變量可以在定義時賦予初始值,此時需要將每個成員的值分別用大括號括起來。例如:structstudent{charno[10];charname[20];intmath;inteng;intchin;floatsum;}s1={"11","abc",56,78,89,0};上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
在定義結(jié)構(gòu)體數(shù)組時,可以為每個數(shù)組元素指定初始值。例如:structstudent{charno[10];charname[20];intmath;inteng;intchin;floatsum;}s[2]={{"11","Tom",56,78,89,0},{"22","Jerry",88,68,96,0}};上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
指針變量指向一個結(jié)構(gòu)體變量,
指針變量中存儲的值為該結(jié)構(gòu)體變量占據(jù)存儲空間的首地址。例如,STU類型指針ps可以通過初始化或賦值操作,讓指針ps指向一個結(jié)構(gòu)體變量:ps=&s1;指針ps存儲s1的存儲地址。當然,ps也可以初始化為一個新申請的結(jié)構(gòu)體空間地址:ps=(STU?)malloc(sizeof(STU));上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
8.1.3
訪問結(jié)構(gòu)體成員在定義了結(jié)構(gòu)體變量后,訪問結(jié)構(gòu)體各成員的語法格式如下:結(jié)構(gòu)體變量名成員名符號“”是成員運算符,其優(yōu)先級高于&(地址運算符)、!(邏輯非運算符)、++(前綴自增運算符)、--(前綴自減運算符)等一元運算符。定義了結(jié)構(gòu)體的指針變量后,引用各成員的語法格式如下:結(jié)構(gòu)體指針變量名->成員名結(jié)構(gòu)體變量的成員可以像普通變量一樣進行各種運算和操作。例如:s1no="33";strcpy(s2name,"Jack");ps->sum=0;上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
相同類型的結(jié)構(gòu)體變量可以互相賦值。例如:students2=s1;這樣,s2和s1的每個成員都具有相同的值。結(jié)構(gòu)體變量的成員可以作為獨立的函數(shù)參數(shù)進行傳遞。
相對應的形參類型應與實參類型一致,實參將值傳遞給形參作為初始值。被調(diào)函數(shù)在執(zhí)行過程中,即使形參的值發(fā)生了改變,對應的實參值也不會改變。如果結(jié)構(gòu)體成員為數(shù)組或指針類型,將其作為實參,
該實參表示一個地址,則實參與形參之間傳遞的數(shù)據(jù)為地址。
注意:除了賦值之外,結(jié)構(gòu)體變量不能作為一個整體進行輸入/輸出等運算操作。例如,不能這樣使用:printf("%s,%s,%d,%d,%d",s1);上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
8.1.4
結(jié)構(gòu)體作為函數(shù)參數(shù)或返回值1結(jié)構(gòu)體作為函數(shù)參數(shù)結(jié)構(gòu)體變量或指針可以像普通變量一樣作為函數(shù)參數(shù)。本節(jié)以輸出學生信息為例,比較兩種函數(shù)定義的區(qū)別,如表8-1所示。在調(diào)用語句“print(s1)”
運行時,
系統(tǒng)生成形參s,
即s1的副本,
將實參s1各個成員的值傳遞給形參s的對應成員。被調(diào)函數(shù)執(zhí)行過程中,形參值發(fā)生了改變,實參值不會相應變化,但增加了形參的內(nèi)存開銷。在調(diào)用語句“print(&s1)”
運行時,
實參傳遞給形參s的是一個結(jié)構(gòu)體的地址&s1,
也就意味著實參s和形參s1指向同一個結(jié)構(gòu)體,在被調(diào)函數(shù)執(zhí)行過程中,通過形參可以訪問該結(jié)構(gòu)體,對該結(jié)構(gòu)體做的任何改變,也就意味著改變了實參所指向的結(jié)構(gòu)體的值。系統(tǒng)為形參s生成的只是一個指針空間,遠遠小于一個結(jié)構(gòu)體空間,空間開銷小得多。上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
綜上所述,在結(jié)構(gòu)體作參數(shù)的函數(shù)定義中,指向結(jié)構(gòu)的指針代替?zhèn)鬟f結(jié)構(gòu)本身是提升程序運行效率的有效方法。例如,編寫函數(shù)sortBySum實現(xiàn)按學生總成績排序,將student類型的數(shù)組作為形參,即結(jié)構(gòu)體的指針作為形參;編寫函數(shù)print實現(xiàn)學生信息的輸出,同樣選用指向結(jié)構(gòu)體的指針作為參數(shù)。上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
實現(xiàn)例8-1的程序代碼如下:上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
2結(jié)構(gòu)體作為函數(shù)返回值結(jié)構(gòu)體變量或指針可以像普通變量一樣作為函數(shù)返回值。本節(jié)以輸入學生信息為例,比較兩種函數(shù)定義的區(qū)別,如表8-2所示。當調(diào)用語句“STUs1=get("11","Tom",56,78,89)”
執(zhí)行時,
主調(diào)函數(shù)將分配一段空間,用于存放返回的結(jié)構(gòu)體,即s1。在子函數(shù)get退出時,主調(diào)函數(shù)可以訪問到返回的結(jié)構(gòu)體s1。當調(diào)用語句“STU?ps1=get("11","Tom",56,78,89)”
執(zhí)行時,
被調(diào)函數(shù)get會利用malloc在堆中生成結(jié)構(gòu)體空間。在被調(diào)函數(shù)get退出時,主調(diào)函數(shù)可以獲得該結(jié)構(gòu)體的首地址。但是,這種使用方式存在問題:被調(diào)函數(shù)get使用了malloc申請內(nèi)存空間,但是沒有與之對應的free函數(shù)釋放該內(nèi)存空間。此時,主調(diào)函數(shù)應完成釋放內(nèi)存的操作,否則會導致內(nèi)存泄漏。上一頁下一頁返回8.1結(jié)構(gòu)體的定義與使用
例如,主調(diào)函數(shù)含有下列調(diào)用語句,可釋放堆內(nèi)存:STU?ps1=get("11","Tom",56,78,89);print(ps1);free(ps1);上一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
實訓1
計算三維空間中兩點之間的距離輸入三維空間中的兩點,輸出兩點之間的距離。1實訓分析將三維空間的點組成一個整體,定義為結(jié)構(gòu)體point3D,然后輸出二者之間的距離。需要引用庫函數(shù)mathh。算法的偽代碼如下:(1)定義結(jié)構(gòu)體point3D,
包含成員x、
y、
z等三維信息;(2)輸入兩點的坐標值;(3)利用距離公式計算兩點之間的距離,
并輸出。下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
程序的代碼如下:上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
2實訓練習(1)定義date結(jié)構(gòu)體類型,包含三個成員:month、day和year(都為int型),編寫程序,包含兩個子函數(shù)。一個函數(shù)的原型為
“intdayof_year(structdated)”
,其功能是計算日期d是一年中的第幾天
(1~366的整數(shù)),并將其值返回。另一個函數(shù)的原型為
“intcom-pare_dates(sturctdated1,sturctdated2)”,其功能是比較日期d1和d2的關系。如果日期d1在d2之前,就返回-1;如果d1在d2之后,就返回1;如果d1和d2相等,就返回0。在主程序中分別驗證兩個函數(shù)的正確性。上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
(2)假定time結(jié)構(gòu)體包含三個成員:hours、
minutes和seconds(都為int型)。
編寫程序,
其中包含函數(shù)structtimesplit_time(longtotal_seconds),
total_seconds是從午夜開始的秒數(shù),
函數(shù)返回一個包含等價時間的結(jié)構(gòu)體,
等價的時間用小時(0~23)、
分鐘(0~59)和秒(0~59)表示。上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
實訓2
利用結(jié)構(gòu)體數(shù)組存儲一元多項式并輸出以指數(shù)遞增的順序輸入一個多項式系數(shù)和指數(shù),并使用結(jié)構(gòu)體數(shù)組存儲,按一定格式輸出多項式。1實訓分析在數(shù)學上,
一個一元多項式可以按照升冪表示為A(x)=a0+a1x+a2x2
+···+anxn,
它由n+1個系數(shù)唯一確定。然而,在實際應用中,多項式的指數(shù)可能很高且變化很大,多項式的系數(shù)大多為零。例如,多項式5+6x-10x100由101個系數(shù)確定,但這些系數(shù)多數(shù)為零。因此,
存儲多項式時,
每項可包括系數(shù)和指數(shù),
如多項式5+6x-10x100可存儲(5,0),(6,1),(-10,100)等三項內(nèi)容。我們定義一個結(jié)構(gòu)體,包含coef和exp兩個成員。coef表示系數(shù),為float型;exp表示指數(shù),為int型。一個一元多項式可存儲為一個該結(jié)構(gòu)體類型數(shù)組。上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
算法的偽代碼如下:(1)定義節(jié)點結(jié)構(gòu)體term與數(shù)組poly;(2)輸入多項式的多組系數(shù)和指數(shù),
計數(shù)器n初始化為0;(2.1)將一組系數(shù)和指數(shù)存入數(shù)組元素poly[n];(2.2)n++;(2.3)如果當前字符為回車符,
則輸入結(jié)束;(3)將多項式按格式輸出。上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
程序的代碼如下:上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
2實訓練習編寫一個程序,輸入N個用戶的姓名和電話號碼,按照用戶姓名的詞典順序輸出用戶的姓名和電話號碼。上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
實訓3
創(chuàng)建簡單鏈表提交三個同學的學號與一門課程的考試成績,編程建立這三組數(shù)據(jù)節(jié)點組成的簡單鏈表。1實訓分析鏈表就是靈活擴展長度的數(shù)據(jù)結(jié)構(gòu)。鏈表類似于珍珠項鏈,由多個節(jié)點通過指針的指向連接在一起,每個節(jié)點都有獨立的存儲空間,一個節(jié)點的存儲空間是連續(xù)的,但多個節(jié)點的存儲空間可以是不連續(xù)的。本題包含三項數(shù)據(jù),可以申請三個分散的節(jié)點空間,分別存儲這三項的學號和成績,但它們都是分散的,需要用線將其串起來。也就是說,第1個節(jié)點記住第2個節(jié)點的地址,第2個節(jié)點記住第3個節(jié)點的地址,第3個節(jié)點則不需記憶。我們只需獲得第1個節(jié)點的地址就可以找到所有節(jié)點。上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
指針可以完成記錄地址的工作,所以每個節(jié)點都有一個指針區(qū)域用于記錄另一個節(jié)點的地址,若不需要記錄地址,該指針值為空(即空指針),則可以用C語言定義的符號常量NULL來表示。圖8-2顯示了一個樣例的鏈表示意,指針p、q、r分別記錄了三個節(jié)點的地址。
指針p指向的第1個節(jié)點包含了一個指針域,該指針域記錄了第2個節(jié)點的地址。同理,指針q指向的第2個節(jié)點的指針域記錄了第3個節(jié)點的地址。但是,r指向的第3個節(jié)點的指針域為空,沒有記錄任何地址。上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
圖8-2中的節(jié)點結(jié)構(gòu)可如下定義:typedefstructnode{intnum;intscore;structnode?next;}Node;其中,結(jié)構(gòu)體內(nèi)部指針域next記錄下一個節(jié)點的地址,是指向structnode類型的指針。算法的偽代碼如下:(1)定義結(jié)構(gòu)體類型node和三個結(jié)構(gòu)體指針變量p、
q、
r;(2)申請三個結(jié)構(gòu)體節(jié)點空間,
p、
q、
r分別記錄其首地址;(3)使用指針將三個節(jié)點相連,
p->next=q;
q->next=r;
r->next=NULL。上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
程序的代碼如下:上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
2實訓練習將實訓3的節(jié)點數(shù)目增加到10個,建立一個包含10個節(jié)點的鏈表。上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
實訓4
使用鏈表存儲一元多項式并輸出以指數(shù)遞增的順序輸入一個多項式的多組系數(shù)和指數(shù),并使用鏈表存儲,按一定格式輸出多項式。1實訓分析使用結(jié)構(gòu)體數(shù)組存儲多項式是一種簡單靜態(tài)存儲方法,
但定義數(shù)組時并不能確定多項式中包含多少項,極易造成空間的浪費,并且也容易造成多項式運算的低效和不靈活性。因此,多項式的存儲應采用更科學的存儲方法,鏈表是最佳選擇。例如,多項式12+25x+32x2-25x5的鏈表示意圖如圖8-3所示。上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
圖8-3中的head為指針變量,記錄了第1個節(jié)點的地址。每個節(jié)點存儲的內(nèi)容為一個整體,可定義一個結(jié)構(gòu)體類型來表示。代碼如下:structnode{floatcoef; /?系數(shù)?/intexp; /?指數(shù)?/structnode?next;}?head;其中,指針head為structnode類型的指針變量,其值是節(jié)點的地址。上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
或者,使用結(jié)構(gòu)體的嵌套結(jié)構(gòu)表示節(jié)點。將節(jié)點中的前兩項看作一個整體,定義一個結(jié)構(gòu)體類型structelem。然后,將structelem類型數(shù)據(jù)與指針合并成一個整體,定義一個結(jié)構(gòu)體類型structnode。代碼如下:structelem{floatcoef; /?系數(shù)?/intexp; /?指數(shù)?/};structnode{structelemdata;structnode?next;}?head;上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
上述兩種定義引用結(jié)構(gòu)成員方式不同。例如,引用一個節(jié)點的系數(shù),第1種定義的引用方式如下:head->coef;第2種定義的引用方式如下:head->data->coef;上述兩種定義均可使用表達式head->next來獲取第2個節(jié)點的地址。存儲多項式就是建立鏈表的過程,需要完成的工作有:(1)申請節(jié)點p;(2)將前一個節(jié)點pre的指針域填入p,
即兩個節(jié)點用指針連接;(3)記住第1個節(jié)點的地址,
存入指針head。上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
綜上所述,算法的偽代碼如下:(1)定義節(jié)點結(jié)構(gòu),
將指針head、
p、
pre初始化為NULL;(2)輸入多項式的多組系數(shù)和指數(shù),
以回車鍵結(jié)束,
循環(huán)變量i初始化為0;(2.1)申請節(jié)點p,
將一組系數(shù)和指數(shù)存入節(jié)點;(2.2)記住第1個節(jié)點的地址。
如果i==0,
則head=p;(2.3)將節(jié)點p與前一個節(jié)點使用指針連接。
若pre!=NULL,
則pre->next=p;(2.4)pre=p;
i++;(3)將最后一個節(jié)點的指針域置為空,
p->next=NULL;上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
(4)p初始化為head,
while(p!=NULL)輸出多項式的每項內(nèi)容;(4.1)輸出系數(shù)、
指數(shù)與x的組合;(4.2)p=p->next;(5)while(head!=NULL)釋放節(jié)點空間:(5.1)p=head;(5.2)釋放節(jié)點p;(5.3)head=head->next;上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
程序的代碼如下:上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
上一頁下一頁返回8.2結(jié)構(gòu)體實訓與實訓指導
2實訓練習使用函數(shù)將程序8-3的主函數(shù)簡化。例如,將建立鏈表部分編寫一個函數(shù),將鏈表輸出部分編寫一個函數(shù),將銷毀所有節(jié)點部分編寫一個函數(shù),而主函數(shù)只需調(diào)用自定義函數(shù)即可。上一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
8.3.
1
文件的打開與關閉1使用fopen函數(shù)打開文件打開一個文件,需要調(diào)用fopen函數(shù)。該函數(shù)的原型如下:FILE?fopen(char?filename,char?mode);各參數(shù)說明如下:(1)filename:該參數(shù)是一個字符串,
指定要打開的文件名,
其中可以包含文件的位置信息。
例如,
“abctxt”
表示打開當前目錄下的abctxt文件,
“c:\\clanguage\\testdat”
表示打開C盤分區(qū)下clanguage目錄下的testdat文件。
注意:不能使用“c:\clanguage\testdat”,因為C語言會把“\t”作為轉(zhuǎn)義字符處理。下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
(2)mode:該參數(shù)是一個字符串,
指定打開文件的使用方式。根據(jù)文件的存儲形式和讀寫操作的不同,文件的使用方式如表8-3所示。在程序設計時,需要根據(jù)文件操作的不同需要,選擇相應的打開方式。如果打開方式選擇不正確,就可能導致文件的原有數(shù)據(jù)丟失,或者無法打開文件。無法打開文件時,fopen函數(shù)會返回一個空指針值NULL,即零值。fopen函數(shù)返回一個文件指針,我們可以定義一個文件類型指針變量來存儲函數(shù)返回值。隨后對文件進行其他操作時,將用到這個文件指針。例如:FILE?fp;fp=fopen("testdat","r");上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
2使用fclose函數(shù)關閉文件文件關閉函數(shù)的作用是斷開由fopen函數(shù)建立的文件指針與文件之間的連接。相當于在編輯完Word文檔后,將其關閉。
其函數(shù)原型如下:intfclose(FILE?pfile)其中,文件指針必須已經(jīng)存在,即已使用fopen函數(shù)打開了一個文件,并使該指針變量指向該文件。上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
3文件中的位置指針文件中的位置指針類似于向屏幕輸出數(shù)據(jù)時的光標(光標在什么位置,就在該位置輸出數(shù)據(jù))用于指示當前文件讀寫的位置。在打開文件時,根據(jù)文件的使用方式,位置指針可以指向文件的起始處或末尾處。例如,在使用fopen函數(shù)打開一個文件時,可以使用"a"、"a+"、"ab"、"ab+"這幾種追加方式打開文件,位置指針指向文件的末尾位置;采用其他打開方式,位置指針均指向文件的起始位置。在執(zhí)行讀或?qū)懖僮鲿r,位置指針會自動推進。這樣,程序便可以順序訪問文件中的數(shù)據(jù),或依次向文件中寫入多個數(shù)據(jù)。有時,程序可能需要跳躍式地訪問文件中的數(shù)據(jù),在某位置訪問一些數(shù)據(jù)后,轉(zhuǎn)到另一位置訪問其他數(shù)據(jù)。此時,就需要將位置指針直接定位到文件中某位置,這可以通過文件定位函數(shù)來實現(xiàn)。上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
(1)函數(shù)voidrewind(FILE?stream):設置文件位置指向文件的第1個數(shù)據(jù)。
該函數(shù)不返回任何值。stream是指向FILE對象的指針。(2)函數(shù)intfseek(FILE?stream,longintoffset,intwhence):設置文件位置指向文件的給定偏移處。stream是指向FILE對象的指針。offset是相對whence的偏移量,以字節(jié)為單位。為了避免產(chǎn)生溢出錯誤,編程時可以在移動位移量后面加一個字母L,表示該數(shù)據(jù)為long型。whence表示開始添加偏移offset的位置,
一般指定0(或者SEEK_SET)代表“文件首部”、
1(或者SEEK_CUR)代表“位置指針當前位置”、2(或者SEEK_END)代表“文件末尾”。(3)函數(shù)intfeof(FILE?stream):測試給定流stream的文件結(jié)束標識符。
即文件中位置指針指向文件尾時,該函數(shù)返回一個非零值,否則返回零。上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
8.3.2
文本文件的讀寫下面從一個示例來說明文本文件的讀寫過程。【例8-2】從鍵盤輸入字符串,將字符串寫入文件,然后從文件中讀出字符并顯示?!痉治觥坑墒纠罂芍?,需要新建一個文本文件來存儲字符串,也需要從該文件中讀出字符串。因此,首先需要確定文本文件的文件名及存儲位置;然后,確定打開文件的模式;最后,將鍵盤輸入的字符串寫入文件并關閉文件。我們將文件存儲在當前文件夾中,并將文本文件命名為“abctxt”。將文件打開模式選擇"w+"模式,既可以寫入字符串也可以讀出字符串。在向文件寫入或讀出字符串時,應注意文件指針的變化。上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
算法的偽代碼如下:(1)以"w+"模式新建文本文件“abctxt”
并打開;(2)從鍵盤輸入一串字符串,
利用文本輸入函數(shù)將字符串寫入文本文件“abctxt”;(3)將文件位置指針定位到文件頭;(4)利用文本輸出函數(shù)將文本文件“abctxt”
中的字符串讀出并顯示;(5)關閉文件“abctxt”。上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
1讀/寫字符或字符串函數(shù)打開文件之后,從文件讀取數(shù)據(jù)或把數(shù)據(jù)寫入文件,都需要調(diào)用文件讀寫函數(shù)。C語言提供的文件讀寫字符(或字符串)的函數(shù)有以下幾種:(1)字符輸入函數(shù)intfgetc(FILE?stream):從指定的流stream獲取下一個字符(一個無符號字符),并把位置指針往前移動。該函數(shù)以無符號char型強制轉(zhuǎn)換為int型的形式返回讀取的字符,如果到達文件末尾或發(fā)生讀錯誤,則返回EOF。在stdioh里面定義EOF為1。stream表示從何種數(shù)據(jù)流中讀取,既可以是標準輸入流,也可以是文件流,即從某個文件中讀取。標準輸入流是指輸入緩沖區(qū)stdin,如果從鍵盤讀取數(shù)據(jù),就是從輸入緩沖區(qū)stdin中讀取數(shù)據(jù)。上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
(2)字符輸出函數(shù)intfputc(intchar,FILE?stream):把參數(shù)char指定的字符(一個無符號字符)寫入指定的流stream,并把位置指針往前移動。如果沒有發(fā)生錯誤,則返回被寫入的字符。如果發(fā)生錯誤,則返回EOF,并設置錯誤標識符。stream表示向何種數(shù)據(jù)流輸出,可以是標準輸出流stdout,也可以是文件流。標準輸出流即屏幕輸出。該函數(shù)返回一個非負值,如果發(fā)生錯誤,則返回EOF。(3)字符串輸入函數(shù)char?fgets(char?s,intsize,FILE?stream):從stream流中讀取size個字符存儲到字符,指針變量s所指向的內(nèi)存空間;返回值是一個指針,指向字符串中第1個字符的地址。(4)字符串輸出函數(shù)intfputs(constchar?s,FILE?stream):把字符串寫入指定的流stream,但不包括空字符。返回一個非負值,如果發(fā)生錯誤,則返回EOF。上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
2使用字符或字符串函數(shù)實現(xiàn)文本文件的讀寫【例8-2】從鍵盤輸入字符串并寫入文件?!痉治觥看藭r可以使用函數(shù)fgets和fputs來實現(xiàn)字符串的輸入/輸出,也可以使用函數(shù)fgetc和fputc一次輸入/輸出一個字符。(1)使用函數(shù)fgets和fputs的程序如下:上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
(2)使用函數(shù)fgetc和fputc的程序如下:上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
8.3.3
二進制文件的讀寫前面介紹的fgetc、fputc和fgets、fputs函數(shù)只能從文件中讀取或?qū)懭胱址蛿?shù)據(jù),不能讀寫其他類型的數(shù)據(jù)。這種文件以二進制數(shù)形式存放數(shù)據(jù),稱為二進制文件。下面以一個示例來說明讀取和寫入其他類型數(shù)據(jù)的過程?!纠福场慷x學生結(jié)構(gòu)體變量,輸入5名學生的學號、姓名和三門課程的成績,將所有學生數(shù)據(jù)以二進制數(shù)的方式輸出到文件studentdat中。函數(shù)fun實現(xiàn)功能:重寫形參filename所指文件中最后一個學生的數(shù)據(jù),
即用新的學生數(shù)據(jù){1006,"zhaosi",55,70,68}覆蓋原來的數(shù)據(jù),其他學生的數(shù)據(jù)不變。上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
算法的偽代碼如下:(1)定義結(jié)構(gòu)體類型STU與結(jié)構(gòu)體數(shù)組t[5];(2)以"wb"方式打開文件studentdat;(3)從鍵盤輸入5個學生的數(shù)據(jù)信息,
并將信息輸出到二進制文件studentdat中;(4)用新的學生數(shù)據(jù){1006,"zhaosi",55,70,68}重寫最后一個學生的數(shù)據(jù)。上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
1二進制文件的輸入/輸出函數(shù)fread和fwrite函數(shù)一般用于二進制文件的輸入與輸出。fwrite和fread函數(shù)在stdioh中的聲明方式如下:(1)函數(shù)intfread(void?ptr,intsize,intnmemb,FILE?stream):從給定流stream讀?。睿恚澹恚鈧€size大小的數(shù)據(jù)存儲到ptr所指向的數(shù)組中,返回成功讀取的元素總數(shù)。如果總數(shù)與nmemb參數(shù)不同,則可能發(fā)生了一個錯誤或者到達文件末尾。(2)函數(shù)intfwrite(constvoid?ptr,intsize,intnmemb,FILE?stream):把ptr所指向的數(shù)組中nmemb個size大小的數(shù)據(jù)寫入給定流stream。如果寫入成功,則該函數(shù)返回寫入元素的總數(shù)。如果該數(shù)據(jù)與nmemb參數(shù)不同,則會顯示一個錯誤。上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
2使用二進制文件輸入/輸出函數(shù)來實現(xiàn)文件的讀寫以例8-3為例,使用fread和fwrite函數(shù)將5個學生的數(shù)據(jù)輸出到文件指針fp指向的文件語句如下:fwrite(t,sizeof(STU),5,fp);其中,
學生結(jié)構(gòu)體數(shù)據(jù)類型為STU,
STU數(shù)組為t[5]。
如果在文件中重寫最后一個學生的數(shù)據(jù),則需要將位置指針定位到最后一個學生數(shù)據(jù)之前。實現(xiàn)語句如下:fseek(fp,-(long)sizeof(STU),1,SEEK_END);該語句表示從文件尾向前移(負號前移,正號后移),移動大小為一個結(jié)構(gòu)體類型STU的大小。為了避免產(chǎn)生溢出錯誤,編程時可以在移動位移量后面加一個字母L,表示該數(shù)據(jù)為long型,或?qū)⑵屏繌娭妻D(zhuǎn)換為長整型。上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
此外,還可以采用從文件頭向后移。實現(xiàn)語句如下:fseek(fp,(long)(5-1)?sizeof(STU)),SEEK_SET);將例8-3使用二進制文件輸入/輸出函數(shù)的程序如下:上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
8.3.4
文件的格式化輸入與輸出使用fscanf和fprintf函數(shù)可以按指定格式向文件中輸入/輸出多種類型的數(shù)據(jù),類似于格式化輸入/輸出函數(shù)scanf函數(shù)和printf函數(shù)。函數(shù)庫stdioh對這兩種函數(shù)的聲明如下:(1)函數(shù)intfprintf(FILE?stream,constchar?format,):發(fā)送格式化輸出到stream,其格式輸出方式與函數(shù)printf相同。(2)函數(shù)intfscanf(FILE?stream,constchar?format,):從stream讀取格式化輸入,格式輸入方式與函數(shù)scanf相同。上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
【例8-4】以第4章實訓2中輸出三角形乘法表為例,將其輸出到文件“multidat”,然后讀出文件內(nèi)容,將其輸出到屏幕。程序的代碼如下:上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁下一頁返回8.3使用FILE結(jié)構(gòu)體類型的文件操作
上一頁返回8.4共用體
共用體有時也稱為聯(lián)合或聯(lián)合體,這也是單詞union的本意,是一種節(jié)省空間的定義方法,經(jīng)常出現(xiàn)在結(jié)構(gòu)體的定義中。結(jié)構(gòu)體各成員擁有自己獨立的存儲空間,互相不重疊,所占存儲空間的長度是各成員所占存儲空間的長度之和。共用體的幾個不同類型的成員共用一塊存儲空間,該存儲空間在某一時刻只能由一個數(shù)據(jù)使用。本節(jié)通過一個示例來說明使用共用體的必要性。下一頁返回8.4共用體
【例8-5】輸入表8-4所示的學生成績信息,保存至文件“stuscoredat”。學生成績信息包括學號(sno)、
姓名(sname)、
課程名稱(cname)、
課程屬性(cproperty)、
課程成績(cresult)等?!痉治觥坑桑福惫?jié)可知,表中結(jié)構(gòu)可以建立結(jié)構(gòu)體類型。該結(jié)構(gòu)體包括表中的5類信息,其中cproperty有兩個取值:必修和選修。課程屬性不同則課程成績不同。必修課的成績(cresult)為百分制成績,
選修課成績(cresult)為等級制成績———優(yōu)秀、
良好、
中等、及格、不及格。那么,課程成績含有兩種不同的數(shù)據(jù)類型。一種為浮點型;另一種為字符數(shù)組。
因此,
需要將課程成績(cresult)定義為共用體類型。上一頁下一頁返回8.4共用體
8.4.1
共用體類型及其變量的定義
一個共用體所占存儲空間的長度等于成員的存儲空間長度的最大值。
共用體類型的定義形式如下:union共用體名{成員列表}共用體變量列表;共用體名是可選的,可以省略。每個成員是標準的變量定義,如“inti;”或“floatf;”或其他有效的變量定義。在共用體定義的末尾,最后一個分號之前,可以指定一個或多個共用體變量,這是可選的。上一頁下一頁返回8.4共用體
例如,建立兩種成績的共用體,代碼如下:unionresult{floatscore;chargrade[4];}u;u為共用體變量。共用體變量也可如下定義:unionresultt;上一頁下一頁返回8.4共用體
成員相同的結(jié)構(gòu)體可如下定義:struct{floatscore;chargrade[4];}s;上述結(jié)構(gòu)體變量s與共用體u只有一處不同:s的成員存儲在不同的存儲空間中,而u的成員存儲在同一塊內(nèi)存空間中。s和u在內(nèi)存中的存儲情況如圖8-4所示(假設float型的值要占用4個字節(jié),而char型的值占用1字節(jié))。在結(jié)構(gòu)體變量s中,score域與grade域占用不同的內(nèi)存空間,共占用9個存儲單元;在共用體變量u中,score域與grade域相互交迭,只占用4個存儲單元,二者具有相同的存儲地址。上一頁下一頁返回8.4共用體
訪問共用體成員的方法和訪問結(jié)構(gòu)成員的方法相同。例如,把成績805存儲到u的成員score中,
可以寫成:uscore=805;又如,把成績'A'存到u的成員grade中,可以寫成:ugrade='A';因為共用體的成員重疊存儲,所以改變一個成員就會改變其他成員的值。也就是說,將一個值存入ugrade中,那么,之前存儲在uscore中的值將丟失。因此,u為存儲score或grade的空間,而不是同時存儲二者的空間。上一頁下一頁返回8.4共用體
思考:假設s為如下結(jié)構(gòu):上一頁下一頁返回8.4共用體
u為如下聯(lián)合:如果char型的值占1字節(jié),int型的值占4字節(jié),而double型的值占8字節(jié),那么C編譯器為s和u分配多大的空間呢?(假設編譯器沒有在成員之間留“空洞”)上一頁下一頁返回8.4共用體
8.4.2
共用體的使用在結(jié)構(gòu)體中,經(jīng)常使用共用體用于節(jié)省空間。例如,在上述的學生成績表中,
課程成績有兩種不同的數(shù)據(jù)類型,如果將學生成績表的結(jié)構(gòu)表示為結(jié)構(gòu)類型,可如下定義:structstuscore{charsno[11];charsname[20];charcname[20];charcproperty[4];floatscore; /?百分制成績?/chargrade[4]; /?等級制成績?/};上一頁下一頁返回8.4共用體
雖然上述結(jié)構(gòu)非常好用,但是這種類型非常浪費空間。當課程性質(zhì)為必修課時,成員grade不需要存儲內(nèi)容;而當課程性質(zhì)為選修課時,成員score不需要存儲內(nèi)容。此時,使用共用體是一個很好的選擇。當需要存儲百分制成績時,存儲類型為float型,當需要存儲等級制成績時,存儲類型為char型。我們在結(jié)構(gòu)體中定義共用體,使grade域和score域共用一塊空間。上一頁下一頁返回8.4共用體
例8-5的結(jié)構(gòu)可如下定義:structstuscore{charsno[11];charsname[20];charcname[20];charcproperty[4];union{floatscore;chargrade[4];}cresult;};上一頁下一頁返回8.4共用體
例8-5的程序代碼如下:上一頁下一頁返回8.4共用體
上一頁下一頁返回8.4共用體
上一頁下一頁返回8.4共用體
上一頁下一頁返回8.4共用體
上一頁下一頁返回8.4共用體
上一頁下一頁返回8.4共用體
【練習】假設s為如下結(jié)構(gòu):上一頁下一頁返回8.4共用體
其中,RECTANGLE和CIRCLE為預定義的常量:#defineRECTANGLE1#defineCIRCLE2point結(jié)構(gòu)如下:structpoint{intx,y;};上一頁下一頁返回8.4共用體
編寫3個函數(shù),用來在shape類型結(jié)構(gòu)變量s上完成下列操作,并在主函數(shù)中驗證:(1)計算s的面積,
并返回s的面積。(2)將s沿x軸方向移動x個單位,
沿y軸移動y個單位,
返回s修改后的內(nèi)容。(x、
y是函數(shù)的另外兩個參數(shù))(3)把s縮放c倍(c是double型的值),
返回s修改后的內(nèi)容。(c是函數(shù)的另一個參數(shù))上一頁返回8.5枚舉類型
在實際應用中,我們需要某些變量具有少量有意義的值。例如,邏輯真和邏輯假表示兩種邏輯值,這種變量稱為布爾變量或邏輯變量;用來存儲一星期中七天的變量有7種可能的值;用來存儲撲克牌花色的變量有4種可能的值。若定義一個變量用于表示一星期中的七天,實現(xiàn)方法一般有以下兩種。1.定義整型變量可一組編碼來表示變量的可能值:intweekday;weekday為1,表示星期一;weekday為2,表示星期二;依次類推。缺
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 化工催化技術(shù)課件
- 化工仿真培訓實操課件
- 飛秒技術(shù)科普
- 2026年人力資源管理師績效考核體系設計知識練習(含答案解析)
- 2026云南保山市騰沖市邊防辦招聘邊境專職聯(lián)防員備考考試題庫及答案解析
- 2026年青島市即墨區(qū)部分事業(yè)單位公開招聘工作人員(53人)筆試備考試題及答案解析
- 2026云南嘉華食品有限公司招聘備考考試題庫及答案解析
- 別墅搭架施工方案(3篇)
- 標識制作施工方案(3篇)
- 電力配電施工方案(3篇)
- 藥物分析個人述職報告
- 供應鏈金融居間合同
- PVC結(jié)構(gòu)拉縫板技術(shù)交底
- DB43∕T 389-2010 安化黑茶千兩茶
- 輸變電標志牌安裝施工方案
- 無張力尿道懸吊術(shù)護理
- 翰威特:2010年翰威特員工敬業(yè)度調(diào)研簡介
- DL∕T 5210.6-2019 電力建設施工質(zhì)量驗收規(guī)程 第6部分:調(diào)整試驗
- 新生兒機械通氣指南
- 2023年PCB工程師年度總結(jié)及來年計劃
- 績效考核和薪酬方案通用模板
評論
0/150
提交評論