《C語言程序設(shè)計(jì)基礎(chǔ)》課件第9章_第1頁
《C語言程序設(shè)計(jì)基礎(chǔ)》課件第9章_第2頁
《C語言程序設(shè)計(jì)基礎(chǔ)》課件第9章_第3頁
《C語言程序設(shè)計(jì)基礎(chǔ)》課件第9章_第4頁
《C語言程序設(shè)計(jì)基礎(chǔ)》課件第9章_第5頁
已閱讀5頁,還剩105頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

第9章

用戶可建立的數(shù)據(jù)類型——復(fù)雜數(shù)據(jù)

的表示與處理9.1結(jié)構(gòu)體9.2共用體9.3枚舉類型9.4用戶自定義數(shù)據(jù)類型名稱9.5用結(jié)構(gòu)體和指針處理鏈表實(shí)訓(xùn)任務(wù)十七

熟悉結(jié)構(gòu)體、共用體數(shù)據(jù)類型的表示與使用實(shí)訓(xùn)任務(wù)十八

學(xué)習(xí)復(fù)雜數(shù)據(jù)表示處理的編程方法 9.1結(jié)

構(gòu)

9.1.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量的定義

1.先定義結(jié)構(gòu)體類型,再定義結(jié)構(gòu)體變量

定義結(jié)構(gòu)體類型的一般形式為

其中,“struct”為結(jié)構(gòu)體類型定義關(guān)鍵字,是結(jié)構(gòu)體類型的標(biāo)識符?!敖Y(jié)構(gòu)體類型名”是所定義結(jié)構(gòu)體的類型名稱,這個名字由用戶命名,其命名同變量名、數(shù)組名一樣,要符合C語言的標(biāo)識符命名規(guī)則。用戶可以用該類型名來定義結(jié)構(gòu)體變量?;ɡㄌ栔卸x該結(jié)構(gòu)體類型所包含的成員,即成員的類型、名稱及其順序關(guān)系。成員名的命名規(guī)則與標(biāo)識符命名規(guī)則相同。成員類型可以是基本類型或者任何在該結(jié)構(gòu)體類型之前已經(jīng)定義過的自定義類型。結(jié)構(gòu)體類型的定義僅是聲明了一種數(shù)據(jù)對象的結(jié)構(gòu)類型,僅表示一種抽象結(jié)構(gòu),并不代表具體的數(shù)據(jù)對象,編譯系統(tǒng)也不分配存儲空間,不能在程序中引用。要使所定義的結(jié)構(gòu)體類型代表一個數(shù)據(jù)對象,需定義結(jié)構(gòu)體類型變量。定義結(jié)構(gòu)體類型變量的一般方式為

struct結(jié)構(gòu)體類型名變量名;

其中,“struct結(jié)構(gòu)體類型名”代表一種結(jié)構(gòu)體類型,其后的變量名就被定義為可表示該結(jié)構(gòu)體類型的變量,變量表示具有該結(jié)構(gòu)體的實(shí)體對象,編譯系統(tǒng)給結(jié)構(gòu)體變量按結(jié)構(gòu)體成員順序與類型分配存儲空間。

“date”是結(jié)構(gòu)體類型的名稱,year、month和day分別是整型數(shù)據(jù)成員的名稱,表示日期中的年、月、日。

定義了結(jié)構(gòu)體類型之后,就可以用該類型來定義結(jié)構(gòu)體變量。如:

structdatedate1;

“date1”是被定義為表示日期類型的結(jié)構(gòu)體變量。其存儲結(jié)構(gòu)是連續(xù)分配3個整型數(shù)據(jù)的單元,一個整型數(shù)據(jù)占4個字節(jié),共占12個字節(jié)的存儲空間。

結(jié)構(gòu)體類型定義中,成員類型可以是已經(jīng)定義過的任何一種數(shù)據(jù)對象的類型。例如,在定義了日期結(jié)構(gòu)體類型的基礎(chǔ)上,可定義一個學(xué)生信息的結(jié)構(gòu)體類型:學(xué)生結(jié)構(gòu)體類型定義中包含日期結(jié)構(gòu)體成員birthday,即結(jié)構(gòu)體類型可以嵌套定義。但是,結(jié)構(gòu)體不允許遞歸定義,即結(jié)構(gòu)體的成員不能為該結(jié)構(gòu)體的變量。如,下面的定義是非法的:

在定義了“student”結(jié)構(gòu)體類型的基礎(chǔ)上,可以定義該結(jié)構(gòu)體類型的變量:

structstudentstudent1,student2;

從上述可以看出,由一個結(jié)構(gòu)體類型可以定義多個結(jié)構(gòu)體變量。

2.在定義結(jié)構(gòu)體類型的同時定義結(jié)構(gòu)體變量

該方式定義的一般形式為

從上述可知,定義結(jié)構(gòu)體類型的目的是定義結(jié)構(gòu)體變量,只有結(jié)構(gòu)體變量才能存儲和處理結(jié)構(gòu)體數(shù)據(jù),前兩種方式定義了結(jié)構(gòu)體類型名稱,可以使用這種結(jié)構(gòu)體類型名稱來定義新的結(jié)構(gòu)體變量。第3種定義方式,沒用結(jié)構(gòu)體類型名,無法利用結(jié)構(gòu)體類型名來定義新的結(jié)構(gòu)體變量。

結(jié)構(gòu)體成員可以與程序中的其他變量同名,兩者代表不同對象,互不影響。結(jié)構(gòu)體的定義可以放在函數(shù)內(nèi),也可以放在函數(shù)外。在函數(shù)內(nèi)定義的結(jié)構(gòu)體只能在函數(shù)內(nèi)使用(即局部數(shù)據(jù)對象)。在函數(shù)外定義的結(jié)構(gòu)體可以在定義點(diǎn)之后的所有函數(shù)內(nèi)使用(全局?jǐn)?shù)據(jù)對象)。

9.1.2結(jié)構(gòu)體變量的初始化

如何給結(jié)構(gòu)體變量提供初始數(shù)據(jù)?

定義了結(jié)構(gòu)體變量后,系統(tǒng)按成員的順序和類型給其分配存儲空間,但成員沒有指定的數(shù)據(jù)。對結(jié)構(gòu)體提供數(shù)據(jù)是針對成員來進(jìn)行的,也就是說,不能對結(jié)構(gòu)體整體進(jìn)行,這與數(shù)組類似。對結(jié)構(gòu)體成員提供數(shù)據(jù)有兩種方式,一種是在定義結(jié)構(gòu)體變量時提供初始值,稱為初始化;還有一種是在程序運(yùn)行中,通過賦值操作給成員提供值。一般在定義結(jié)構(gòu)體變量時,需進(jìn)行初始化。結(jié)構(gòu)體變量初始化的方式是:按結(jié)構(gòu)體成員的順序和類型分別提供初始數(shù)據(jù)。例如,對前面定義的學(xué)生結(jié)構(gòu)體變量初始化如下:

structstudentstudent1={0103208,"liuxiqiao",'w',{1983,9,17}};

給結(jié)構(gòu)體變量賦初值要用花括號將所有成員數(shù)據(jù)括起來。在花括號中要按成員順序提供初始數(shù)據(jù),數(shù)據(jù)類型要與定義的成員類型一致。例如“姓名”成員是字符數(shù)組,可以通過字符串提供初值,也可以按字符數(shù)組元素的方式提供初值。“出生日期”成員是一個結(jié)構(gòu)體類型,要按定義的日期結(jié)構(gòu)體來提供初值,其年、月、日數(shù)據(jù)用花括號括起來。

9.1.3結(jié)構(gòu)體成員的引用

如何引用結(jié)構(gòu)體變量中的數(shù)據(jù)?

系統(tǒng)把結(jié)構(gòu)體變量看作一個數(shù)據(jù)對象,給其分配數(shù)據(jù)空間,按成員的順序和類型連續(xù)存儲數(shù)據(jù),但對結(jié)構(gòu)體變量的數(shù)據(jù)不能整體引用,只能按成員來引用。結(jié)構(gòu)體數(shù)據(jù)的引用方式與數(shù)組數(shù)據(jù)的引用方式類似。

結(jié)構(gòu)體成員引用的形式為

結(jié)構(gòu)體變量名.成員名

其中,“.”是C語言的一種運(yùn)算符,稱為“取成員運(yùn)算符”?!?”的優(yōu)先級是C語言中優(yōu)先級最高的運(yùn)算符,具有左結(jié)合性(參見附錄C)。例如,前面定義的一個學(xué)生信息的結(jié)構(gòu)體變量,student1.num表示學(xué)號成員數(shù)據(jù)項(xiàng)。

如果成員又是一個結(jié)構(gòu)體類型,則要分層用成員運(yùn)算符,一級一級地找到最基本的成員。例如,要引用一個學(xué)生信息的結(jié)構(gòu)體變量中的出生日期數(shù)據(jù),要分別采用如下的引用

形式:

student1.birthday.year

student1.birthday.month

student1.birthday.day

不能用student1.birthday來引用出生日期數(shù)據(jù)??梢詫Y(jié)構(gòu)體變量中的成員進(jìn)行輸入、輸出、賦值、運(yùn)算等操作。

對結(jié)構(gòu)體成員輸入數(shù)據(jù),要取成員地址。例如:

scanf("%ld",&student1.num);

一個成員變量可以像基本類型變量一樣進(jìn)行相應(yīng)的運(yùn)算。例如:

sum=student1.age+student2.age;

age++;

例9.1

定義一個學(xué)生成績表的數(shù)據(jù)結(jié)構(gòu),學(xué)生信息包含學(xué)號、姓名、出生日期,有5門課成績,從鍵盤輸入數(shù)據(jù),求出學(xué)生總分,輸出學(xué)生數(shù)據(jù)和總分。

編程思路:學(xué)生成績表包含許多學(xué)生數(shù)據(jù),每個學(xué)生具有相同的數(shù)據(jù)結(jié)構(gòu),屬于典型的結(jié)構(gòu)體類型數(shù)據(jù)。先定義學(xué)生數(shù)據(jù)結(jié)構(gòu),再定義學(xué)生數(shù)據(jù)結(jié)構(gòu)的變量。學(xué)生信息的輸入和處理要針對成員數(shù)據(jù)來進(jìn)行。

運(yùn)行結(jié)果:

分析:在程序中定義兩個結(jié)構(gòu)體類型,學(xué)生結(jié)構(gòu)中嵌套了日期結(jié)構(gòu),形成了嵌套結(jié)構(gòu)。定義了結(jié)構(gòu)體變量s來表示具體學(xué)生的結(jié)構(gòu)數(shù)據(jù)。從程序及其運(yùn)行結(jié)果可以看出,結(jié)構(gòu)體成員的輸入/輸出只能按基本類型數(shù)據(jù)元素來進(jìn)行。例如,輸入成員數(shù)組元素采用語句“scanf("%f",&s.score[i]);”,輸出成員數(shù)組元素采用語句“printf("Score%d:%-6.1f",i,s.score[i]);”。

9.1.4結(jié)構(gòu)體數(shù)組

批量結(jié)構(gòu)體類型數(shù)據(jù)如何表示與處理?

在實(shí)際應(yīng)用中,經(jīng)常遇到結(jié)構(gòu)體類型的批量數(shù)據(jù),如一個班級的學(xué)生信息。一個學(xué)生的基本信息是一個結(jié)構(gòu)體類型數(shù)據(jù),一個班級的學(xué)生基本信息就是一個結(jié)構(gòu)體數(shù)組。C語言允許定義結(jié)構(gòu)體數(shù)組。

構(gòu)體數(shù)組是復(fù)合型構(gòu)造數(shù)據(jù)類型,即結(jié)構(gòu)體數(shù)組中所有元素是同一類型的結(jié)構(gòu)體數(shù)據(jù)對象,一個元素是一個結(jié)構(gòu)體數(shù)據(jù)對象。所以,結(jié)構(gòu)體數(shù)組的定義、初始化和元素引用方法都是數(shù)組和結(jié)構(gòu)體中方法的類推。因?yàn)榻Y(jié)構(gòu)體數(shù)組元素是用戶自定義的結(jié)構(gòu)體類型,所以定義結(jié)構(gòu)體數(shù)組應(yīng)先定義元素的結(jié)構(gòu)體類型,然后再按已定義的結(jié)構(gòu)體類型定義數(shù)組。其定義方式與結(jié)構(gòu)體變量的定義方式相仿。只要在結(jié)構(gòu)體變量定義中的變量名位置寫上數(shù)組定義符號即可。結(jié)構(gòu)體數(shù)組定義也有與結(jié)構(gòu)體變量定義對應(yīng)的3種方式。若已定義了結(jié)構(gòu)體類型(具有結(jié)構(gòu)體類型名),則一維結(jié)構(gòu)體數(shù)組定義的一般形式為

struct結(jié)構(gòu)體類型名

數(shù)組名[數(shù)組長度];

其中,“struct結(jié)構(gòu)體類型名”是已經(jīng)定義過的結(jié)構(gòu)體類型,其他和數(shù)組定義一樣。另外兩種定義方式,在后面的例子中說明。同樣也可定義二維結(jié)構(gòu)體數(shù)組。二維結(jié)構(gòu)體數(shù)組不太常用,不再細(xì)述。結(jié)構(gòu)體數(shù)組的初始化是先按元素順序,再按元素的結(jié)構(gòu)體成員順序與類型來提供初始數(shù)據(jù)。所以就形成了按元素順序,依次對結(jié)構(gòu)體成員初始化的過程。

對結(jié)構(gòu)體數(shù)組元素的引用也是先引用數(shù)組元素(結(jié)構(gòu)體對象),再引用該元素中的結(jié)構(gòu)體成員。

下面通過一個實(shí)例來說明結(jié)構(gòu)體數(shù)組的定義、初始化和引用的方法。

例9.2

構(gòu)造一個班一門課程成績表的數(shù)據(jù)結(jié)構(gòu),初始化成績表信息,查找出不及格學(xué)生,并輸出該學(xué)生的全部信息。成績表信息包括學(xué)號、姓名、課程、成績。

編程思路:學(xué)生基本信息包含不同類型數(shù)據(jù),應(yīng)是一個結(jié)構(gòu)體類型。一個班成績表應(yīng)是結(jié)構(gòu)體數(shù)組。所以,采用結(jié)構(gòu)體數(shù)組進(jìn)行處理。為簡化數(shù)據(jù),說明處理方法,程序中只對5個學(xué)生信息進(jìn)行處理。

運(yùn)行結(jié)果:

分析:

(1)在程序開頭定義了一個結(jié)構(gòu)體類型,同時定義了結(jié)構(gòu)體數(shù)組st[5],又對數(shù)組進(jìn)行了初始化。內(nèi)層一個花括號對應(yīng)一個數(shù)組元素,花括號內(nèi)的數(shù)據(jù)對應(yīng)一個結(jié)構(gòu)體成員的數(shù)據(jù)??梢钥闯?,數(shù)據(jù)類型與所定義的成員類型一一對應(yīng)。如果去掉結(jié)構(gòu)體類型名“student”,或者把結(jié)構(gòu)體數(shù)組定義放在主函數(shù)中,用“structstudentst[5];”定義,程序都能正確運(yùn)行。請讀者自行驗(yàn)證。

(2)在程序中求總分和輸出不及格學(xué)生的信息中都采用了“數(shù)組名[i].成員名”的引用形式,表示引用數(shù)組第i個元素中指定的成員數(shù)據(jù)。如“st[2].score”是引用結(jié)構(gòu)體數(shù)組第2個元素的結(jié)構(gòu)體成員score的值(即對應(yīng)數(shù)組中的第2個學(xué)生的成績)。

從上例可以看出,只要掌握結(jié)構(gòu)體數(shù)組復(fù)合層次關(guān)系,類推數(shù)組元素的引用到結(jié)構(gòu)體成員的引用方法,對結(jié)構(gòu)體數(shù)組的引用就不難理解。最終都類推到對基本變量的引用上。

9.1.5結(jié)構(gòu)體指針

何謂結(jié)構(gòu)體指針?如何通過結(jié)構(gòu)體指針引用其數(shù)據(jù)?

定義了結(jié)構(gòu)體類型與結(jié)構(gòu)體變量后,系統(tǒng)給結(jié)構(gòu)體數(shù)據(jù)分配一個存儲空間,按照成員順序連續(xù)存儲,按成員類型分別占據(jù)不同字節(jié)的存儲長度,每個成員都有確定的存儲地址,結(jié)構(gòu)體數(shù)據(jù)對象的首地址就是結(jié)構(gòu)體的指針。對結(jié)構(gòu)體數(shù)據(jù)也有兩種訪問方式:直接訪問和間接訪問。前面講的“結(jié)構(gòu)體變量名·成員名”訪問方式就是直接訪問,也可以通過指向結(jié)構(gòu)類型的指針變量,來間接訪問結(jié)構(gòu)體數(shù)據(jù)。結(jié)構(gòu)體數(shù)組存儲結(jié)構(gòu)也同樣保持結(jié)構(gòu)的復(fù)合關(guān)系,先按元素順序連續(xù)存儲,再按成員順序和類型分配存儲空間。每一個結(jié)構(gòu)體元素及其成員都有確定的存儲地址。對結(jié)構(gòu)體數(shù)組數(shù)據(jù)也有兩種訪問方式?!皵?shù)組名[下標(biāo)]·成員名”是直接訪問。同樣,也可以通過指向結(jié)構(gòu)體數(shù)組的指針變量來間接訪問。

掌握了指針及指針變量的實(shí)質(zhì)意義,通過指針變量來訪問結(jié)構(gòu)體及結(jié)構(gòu)體數(shù)組就不難理解了。指向結(jié)構(gòu)體對象的指針變量可指向結(jié)構(gòu)體數(shù)據(jù),也可指向結(jié)構(gòu)體數(shù)組中的元素。指向結(jié)構(gòu)體的指針變量定義、賦初值及通過指針變量引用數(shù)據(jù)的方法同普通指針變量相仿。只是要用自定義的結(jié)構(gòu)體類型來定義指針變量,取結(jié)構(gòu)體類型變量地址賦給指針變量,即可建立指向。例如:

structstudentst; //定義結(jié)構(gòu)體變量

structstudent*p; //定義指向結(jié)構(gòu)體指針變量

p=&st; //使p指向結(jié)構(gòu)體變量st通過指針變量對結(jié)構(gòu)體數(shù)據(jù)的引用有兩種方式:

方式一:

(*指針變量名)·成員名

例如:

(*p)?name;

方式二:

指針變量名->成員名

例如:

p->name;

這兩種方式是等價的,可以相互取代。注意:指針變量名兩側(cè)的括號是不能缺省的。

1.通過結(jié)構(gòu)體指針變量來引用結(jié)構(gòu)體成員值或結(jié)構(gòu)體數(shù)組中的成員值

下面通過兩個例子來說明通過指針變量來引用結(jié)構(gòu)體數(shù)據(jù)和結(jié)構(gòu)體數(shù)組元素。

例9.3

通過指向結(jié)構(gòu)體變量的指針變量輸出結(jié)構(gòu)體變量中成員的信息。

編程思路:為了便于對比,仍以學(xué)生信息表數(shù)據(jù)為例。

運(yùn)行結(jié)果:

分析:在主函數(shù)中定義學(xué)生信息結(jié)構(gòu)體類型的同時定義了結(jié)構(gòu)體變量st,并進(jìn)行了初始化。接著定義了指向結(jié)構(gòu)體類型的指針變量p,&st賦給p,使其指向結(jié)構(gòu)體變量st。兩個printf函數(shù)調(diào)用中,分別采用結(jié)構(gòu)體變量名引用法和指針變量引用法,輸出結(jié)果完全一樣,但意義有所不同,結(jié)構(gòu)體變量名表示結(jié)構(gòu)體數(shù)據(jù)的地址是固定的,指針變量的指向是可以變化的。

分析:程序中定義了指向結(jié)構(gòu)體類型的指針變量ps,把數(shù)組名表示的數(shù)組首地址賦給ps。在for循環(huán)中,“ps=st”使ps指向數(shù)組首元素,“ps++”是數(shù)組邏輯指針的調(diào)整,即使ps指向下一個元素(結(jié)構(gòu)體成員),“ps<st+5”中的st+5仍是一個邏輯指針,表示ps指向最末一個元素后結(jié)束,最末一個元素的指針是st+4。

2.用結(jié)構(gòu)體變量和結(jié)構(gòu)體變量的指針作函數(shù)參數(shù)

從前述已經(jīng)知道,變量作函數(shù)參數(shù),實(shí)參向形參單向傳遞變量的值;指針作函數(shù)參數(shù),實(shí)參向形參傳遞地址,使實(shí)參和形參共同指向一個存儲單元或存儲區(qū),使主調(diào)函數(shù)和被調(diào)函數(shù)共享存儲單元或存儲區(qū)中的數(shù)據(jù)。同樣,結(jié)構(gòu)體變量作函數(shù)參數(shù),實(shí)參向形參傳遞結(jié)構(gòu)體變量中的成員值,即傳遞的是不同類型的多個數(shù)據(jù);結(jié)構(gòu)體變量的指針作函數(shù)的參數(shù),實(shí)參向形參傳遞結(jié)構(gòu)體數(shù)據(jù)對象的地址,使主調(diào)函數(shù)和被調(diào)函數(shù)能共享結(jié)構(gòu)體存儲空間的成員數(shù)據(jù),即能實(shí)現(xiàn)結(jié)構(gòu)體成員數(shù)據(jù)的雙向傳遞。下面通過實(shí)例來說明,請認(rèn)真理解。

例9.5

設(shè)一個班有3門課程的成績表,學(xué)生學(xué)號、姓名已存入系統(tǒng),從鍵盤上錄入學(xué)生3門課成績,求每個學(xué)生的平均成績,并將平均成績最高的學(xué)生信息輸出。

編程思路:學(xué)生成績表屬于結(jié)構(gòu)體數(shù)組結(jié)構(gòu)。從功能上可由3個函數(shù)來實(shí)現(xiàn),顯示學(xué)生學(xué)號、姓名,錄入3門課成績,同時求平均成績;找出最高平均成績;輸出平均成績最高的學(xué)生信息。

運(yùn)行結(jié)果:分析:

(1)定義學(xué)生成績結(jié)構(gòu)體類型,同時定義結(jié)構(gòu)體數(shù)組,只給學(xué)號、姓名成員賦初值;

(2)定義成績錄入并求平均分函數(shù)input,結(jié)構(gòu)體數(shù)組名作參數(shù),系統(tǒng)把數(shù)組名看作指針變量,接收實(shí)參傳遞的指針。屏幕上顯示學(xué)號、姓名,只輸入3門課成績。外循環(huán)控制錄入第i個學(xué)生成績,內(nèi)循環(huán)控制錄入第j門課成績。使用了結(jié)構(gòu)體數(shù)組元素中的成員元素的引用“st[i].score[j]”。

(3)定義找最高平均分函數(shù),結(jié)構(gòu)體數(shù)組名作形參。在循環(huán)中只比較數(shù)組元素的平均分成員項(xiàng)“st[i].aver>st[m].aver”。

(4)定義輸出學(xué)生信息函數(shù),結(jié)構(gòu)體變量作形參,接收實(shí)參傳遞的結(jié)構(gòu)體變量值(全部成員數(shù)據(jù))。

(5)函數(shù)調(diào)用,“input(p);”把指針變量p的值(結(jié)構(gòu)體數(shù)組首地址)傳遞給形參st,使p和st都指向結(jié)構(gòu)體數(shù)組,函數(shù)中錄入的成績就存入結(jié)構(gòu)體數(shù)組的成績數(shù)組中,所求平均分存入平均分成員項(xiàng)中。因?yàn)榻Y(jié)構(gòu)體數(shù)組屬于全局?jǐn)?shù)據(jù)對象,所在函數(shù)中的操作結(jié)果,可供其他函數(shù)使用。

(6)函數(shù)調(diào)用,“print(max(p));”先調(diào)用“max(p)”,把結(jié)構(gòu)體數(shù)組首地址傳遞給形參,在函數(shù)中使用結(jié)構(gòu)體數(shù)組中平均分成員數(shù)據(jù)進(jìn)行比較,返回最高平均分結(jié)構(gòu)體元素st[m],再產(chǎn)生“print(st[m]);”調(diào)用,在函數(shù)中輸出最高平均分學(xué)生的全部信息。

9.2共

9.2.1共用體類型與共用體變量的定義

共用體是用戶自定義的一種數(shù)據(jù)存儲結(jié)構(gòu)類型。必須先定義類型,再定義變量,通過變量來引用共用體中的成員。

共用體定義的一般形式為

其中,union是共用體類型定義關(guān)鍵字;共用體類型名是用戶自定義的類型名稱;花括號中可以是任一類型的數(shù)據(jù)對象,包括自定義類型;共用體變量名表是用戶自定義的共用體類型變量,如果定義多個變量,變量之間要用逗號分隔。

共用體定義同結(jié)構(gòu)體相仿,也有3種定義方式。在上述定義中可以不要“共用體類型名”,也可以在定義共用體類型之后,利用已定義的共用體類型來定義變量。其一般形式為

union共用體類型名共用體變量名表;

定義了共用體類型與變量后,編譯系統(tǒng)按成員中占據(jù)存儲字節(jié)數(shù)最多的成員分配一個存儲單元或空間。

系統(tǒng)給i、ch、f按實(shí)型數(shù)據(jù)分配一個存儲單元,通過變量a可引用3種數(shù)據(jù)之一。其存儲結(jié)構(gòu)如圖9.1所示。為說明問題,假定整型數(shù)占2個字節(jié),實(shí)型數(shù)占4個字節(jié)。

圖9.1共用體存儲結(jié)構(gòu)示意圖9.2.2共用體變量引用

同結(jié)構(gòu)體數(shù)據(jù)引用相仿,共用體變量只能引用其中的成員,也有兩種引用形式。

形式一:

共用體變量名·成員名

形式二:

共用體指針變量名->成員名

因?yàn)楣灿皿w成員通過覆蓋方式共享一個存儲單元或空間,一個變量的瞬時值只能是一個類型的成員值,所以對共用體賦值及引用,一個時刻只能對一個成員進(jìn)行操作。這與結(jié)構(gòu)體變量是截然不同的。關(guān)于共用體變量引用的幾點(diǎn)說明:

(1)共用體變量初始化與賦值。可以對共用體變量初始化,在初始化表中只能有任一成員類型的常量,不能期望同時給各個成員提供初始數(shù)據(jù)。例如:

實(shí)際上是向共用體變量存入一個整型數(shù)。如初始化表為{230,'a',3.6}則是錯誤的。

可以在程序中給共用體變量的成員賦值,但不能給共用體變量賦值。例如:

a.f=3.6;

a.ch='a';

a.i=230;

都是正確的。但如果有a=3.6則是不正確的。

如果有多次賦值,共用體變量中只是最后一次所賦的值,即后面的賦值覆蓋前面的賦值。如上面的賦值語句被執(zhí)行,則引用3個成員的值都是230。

(2)共用體變量的地址和成員的地址是同一地址,即有&a==&a.i==&a.ch==&a.f,因?yàn)?個成員共享一個存儲單元。

下面通過一個例子來說明共用體數(shù)據(jù)的使用。

例9.6

錄入表9.1中的數(shù)據(jù),并輸出。表9.1數(shù)據(jù)信息編程思路:從表中可以看出,教師和學(xué)生信息前四項(xiàng)都是相同的,只有最后一項(xiàng)不同。如果在一個實(shí)際應(yīng)用系統(tǒng)中把學(xué)生和教師信息以單獨(dú)表的結(jié)構(gòu)來存儲、處理,不但會重復(fù)占據(jù)存儲空間,也給程序設(shè)計(jì)帶來一定的麻煩。如果把最后一項(xiàng)作共用體數(shù)據(jù)對象,將會避免上述問題。為說明方法,只編寫一位教師和學(xué)生的信息處理程序。運(yùn)行結(jié)果:

分析:程序中定義了全局結(jié)構(gòu)體數(shù)組person[2],存儲兩個人的信息。在結(jié)構(gòu)體類型定義中嵌套定義了一個共用體變量category,其中有兩個成員,company和charposition[10],身份是學(xué)生,則存班級信息(整型數(shù)據(jù));身份是教師,則存職稱信息(字符數(shù)組)。使用共用體變量,使兩種人員信息統(tǒng)一在一個數(shù)據(jù)結(jié)構(gòu)中。人員信息輸出中,相同信息項(xiàng)作相同處理,只是對不同信息項(xiàng)作選擇處理,簡化了程序設(shè)計(jì),也提高了程序效率。

9.3枚舉類型

一些事物屬性只能列舉,不具有數(shù)值關(guān)系,這些數(shù)據(jù)對象怎樣表示與處理?

現(xiàn)實(shí)中存在一些可列舉的數(shù)據(jù)對象,如一周有星期一到星期日,顏色有紅、橙、黃、綠、青、藍(lán)、紫,等等。這種數(shù)據(jù)對象只可列舉,不具有數(shù)值關(guān)系,似乎難以在計(jì)算機(jī)中處理。C語言允許將這類數(shù)據(jù)定義為枚舉類型,能方便地進(jìn)行處理。

枚舉類型與枚舉變量的定義也同結(jié)構(gòu)體相仿。定義的一般形式為

enum枚舉類型名

{

枚舉元素列表

}枚舉變量列表;

其中,enum為定義枚舉類型的關(guān)鍵字;枚舉類型名是用戶自定義的表示所定義枚舉類型的名稱;“枚舉元素列表”是用逗號分隔的列舉的元素名稱序列;枚舉變量列表是定義枚舉類型的同時定義的變量名。一個枚舉類型可定義多個變量,變量間用逗號分隔,就是枚舉變量列表。枚舉類型與枚舉變量定義也可有3種形式。在上面的定義中可以省略“枚舉類型名”而直接定義枚舉變量。也可以先定義枚舉類型,然后用所定義的枚舉類型來定義枚舉變量。其定義的一般形式為

enum枚舉類型名

枚舉變量列表關(guān)于枚舉數(shù)據(jù)的幾點(diǎn)說明:

(1)枚舉元素雖以標(biāo)號列出,但C編譯系統(tǒng)按常量處理,故稱枚舉常量。在程序中不能給枚舉元素賦值,即枚舉元素相當(dāng)于一個符號常量。

(2)?C編譯系統(tǒng)對枚舉元素按定義的順序依次賦值0,1,2,3,4,5,…。在上面的定義中,Sunday的值為0,Monday的值為1,…,Saturday的值為6。也可在定義時,給枚舉元素指定常量序列值。

(3)枚舉變量的取值范圍是列舉元素值的范圍。如Sunday只可能取0~7之間的一個整數(shù)。

(4)由于枚舉型變量的值是整數(shù),因此C99標(biāo)準(zhǔn)中也把枚舉型作為整型數(shù)據(jù),用整型變量來表示枚舉型元素值。

下面通過一個例子來說明枚舉數(shù)據(jù)的應(yīng)用。

例9.7

一個盒子中有紅、黃、藍(lán)3種顏色的球若干,每次從盒子中先后取出3個球,編程求解取不同顏色球的排列數(shù),并輸出每種顏色排列。

編程思路:定義3種顏色的枚舉類型,再定義3個枚舉類型或整型變量i、j、k,分別表示3個球的顏色值,然后用枚舉算法求取出3個球的顏色排列數(shù)。

枚舉算法:當(dāng)取出的兩個球顏色不同(i≠j)時,取第3個球。如果第3個球與前兩個球顏色都不同(k≠i且k≠j),則是一次有效排列取法,計(jì)數(shù)一次。如此,i、j、k依次取3種顏色值之一,進(jìn)行判斷,可得到求解結(jié)果。顯然應(yīng)該用三重循環(huán)來實(shí)現(xiàn)。

運(yùn)行結(jié)果:

分析:

(1)定義了3種顏色的枚舉類型后,編譯時,3種顏色標(biāo)號依次具有值0、1、2。

(2)定義i、j、k、pri表示顏色取值變量,等價于枚舉變量。

(3)三重循環(huán)實(shí)現(xiàn)3次取球的顏色排列。第3層內(nèi)循環(huán)的if語句要執(zhí)行27次,實(shí)現(xiàn)3次取球的顏色排列判斷。當(dāng)判斷出3個球的顏色不同時,則計(jì)數(shù)變量n+1,將顏色值轉(zhuǎn)換成顏色字符輸出。

(4)將顏色值轉(zhuǎn)換成顏色字符輸出,由if語句中嵌套的for循環(huán)來實(shí)現(xiàn)。當(dāng)判斷3個球顏色不同時,由switch(loop)分別將i、j、k當(dāng)前值賦給pri,再由switch(pri)輸出顏色值對應(yīng)的顏色字符。

(5)使用枚舉類型,使枚舉元素標(biāo)號具有整型值,可以很方便地進(jìn)行比較判斷和相應(yīng)的運(yùn)算。

(6)只要在枚舉類型中添加顏色元素,再于循環(huán)中更改最后一個顏色的取值,即可實(shí)現(xiàn)更多種顏色的取球模型求解。取球模型代表了隨機(jī)抽樣一類應(yīng)用問題。

9.4用戶自定義數(shù)據(jù)類型名稱

1.用新類型名代替原有類型名

其使用的一般形式為

typedef已有類型標(biāo)識符

新類型名;

其作用是用“新類型名”代替原有類型標(biāo)識符,即為原有的一個數(shù)據(jù)類型重新命名,而不是定義一種新的數(shù)據(jù)類型。

2.用一個簡單類型名代替復(fù)雜的類型

諸如數(shù)組類型、結(jié)構(gòu)體類型、共用體類型、枚舉類型等,看起來比較復(fù)雜,可用typedef定義一個簡單的類型名代替復(fù)雜的類型。

9.5用結(jié)構(gòu)體和指針處理鏈表

9.5.1鏈表簡介

鏈表是動態(tài)地進(jìn)行存儲分配的一種數(shù)據(jù)結(jié)構(gòu),特別適合規(guī)模不確定的復(fù)雜數(shù)據(jù)結(jié)構(gòu)的批量數(shù)據(jù)表示與處理問題。例如,在一個學(xué)生成績管理系統(tǒng)中,需要處理多個班級的學(xué)生數(shù)據(jù),每個班學(xué)生數(shù)是不固定的。采用數(shù)組可以表示成績表數(shù)據(jù),但在定義數(shù)組長度時就會產(chǎn)生困惑。按人數(shù)少的班級定義數(shù)組長度,人數(shù)多的班級數(shù)據(jù)不夠用,按人數(shù)多的班級定義數(shù)組長度,則必然造成存儲空間的浪費(fèi)。采用鏈表來表示學(xué)生成績表數(shù)據(jù),可完全解除這種困惑。鏈表是把一個學(xué)生的信息看作一個數(shù)據(jù)節(jié)點(diǎn),成績表數(shù)據(jù)在存儲器中不連續(xù)存儲,通過一個指針把一個班學(xué)生數(shù)據(jù)連接起來,動態(tài)地分配內(nèi)存,即可根據(jù)學(xué)生數(shù)來開辟內(nèi)存空間。鏈表也有多種結(jié)構(gòu),一種簡單的單向鏈表結(jié)構(gòu)如圖9.2所示。圖9.2一種簡單的單向鏈表結(jié)構(gòu)鏈表中,與一個節(jié)點(diǎn)之前連接的節(jié)點(diǎn)稱為該節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn),與一個節(jié)點(diǎn)之后連接的節(jié)點(diǎn)稱為該節(jié)點(diǎn)的后繼節(jié)點(diǎn)。鏈表的中間節(jié)點(diǎn)包含兩個域:一是數(shù)據(jù)域,存放學(xué)生實(shí)際數(shù)據(jù);二是地址域,存放后繼節(jié)點(diǎn)的地址。每一個鏈表都有一個頭節(jié)點(diǎn),只有地址域,存放指向鏈表首節(jié)點(diǎn)的地址。每一個鏈表也有一個尾節(jié)點(diǎn),包含數(shù)據(jù)域,但地址域?yàn)榭?NULL),沒有后繼節(jié)點(diǎn)。每一個節(jié)點(diǎn)的地址都是由系統(tǒng)動態(tài)分配的。

可以看到,表中的元素節(jié)點(diǎn)由地址連接起來。訪問表中節(jié)點(diǎn)數(shù)據(jù),首先要提供頭指針,由頭節(jié)點(diǎn)指針連接表首元素節(jié)點(diǎn),再由此節(jié)點(diǎn)連接下一元素節(jié)點(diǎn),直到表尾節(jié)點(diǎn)。這樣的鏈接方式,如同一個鏈條,一環(huán)扣一環(huán),中間是不能斷開的,所以稱為鏈表。

鏈表中節(jié)點(diǎn)數(shù)據(jù)對象是一個結(jié)構(gòu)體類型。學(xué)生成績表鏈表節(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)可定義如下:

9.5.2建立靜態(tài)鏈表

例9.8

建立由4個學(xué)生信息節(jié)點(diǎn)組成的鏈表,并輸出各節(jié)點(diǎn)中的數(shù)據(jù)。

編程思路:定義節(jié)點(diǎn)數(shù)據(jù)對象為結(jié)構(gòu)體類型,依照連接關(guān)系設(shè)置每個節(jié)點(diǎn)的指針成員,就可形成鏈表。

運(yùn)行結(jié)果:

分析:建立鏈表要經(jīng)歷3個步驟:①根據(jù)節(jié)點(diǎn)數(shù)據(jù)定義節(jié)點(diǎn)結(jié)構(gòu)體,指針成員是不可缺少的;②設(shè)置節(jié)點(diǎn)數(shù)據(jù),只需將數(shù)據(jù)賦給結(jié)構(gòu)體對應(yīng)成員;③建立連接關(guān)系,只需按節(jié)點(diǎn)順序關(guān)系,取結(jié)構(gòu)體變量地址賦值即可。鏈表節(jié)點(diǎn)數(shù)據(jù)輸出,先使指針變量p指向頭節(jié)點(diǎn),輸出頭節(jié)點(diǎn)指針?biāo)赶蚴坠?jié)點(diǎn)數(shù)據(jù),將本節(jié)點(diǎn)指針成員的值賦給p,即指向下一節(jié)點(diǎn),一直到p為NULL。9.5.3建立動態(tài)鏈表

建立動態(tài)鏈表需經(jīng)過以下步驟:

(1)使用動態(tài)分配函數(shù)malloc或calloc申請節(jié)點(diǎn)空間,得到節(jié)點(diǎn)地址,第一次申請節(jié)點(diǎn)為head節(jié)點(diǎn),地址賦給head。

(2)從第1節(jié)點(diǎn)開始,申請節(jié)點(diǎn)得到地

溫馨提示

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

評論

0/150

提交評論