C#程序設(shè)計第11章結(jié)構(gòu)體、聯(lián)合體及位運算_第1頁
C#程序設(shè)計第11章結(jié)構(gòu)體、聯(lián)合體及位運算_第2頁
C#程序設(shè)計第11章結(jié)構(gòu)體、聯(lián)合體及位運算_第3頁
C#程序設(shè)計第11章結(jié)構(gòu)體、聯(lián)合體及位運算_第4頁
C#程序設(shè)計第11章結(jié)構(gòu)體、聯(lián)合體及位運算_第5頁
已閱讀5頁,還剩35頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、第11章結(jié)構(gòu)體、聯(lián)合體與位運算本章介紹結(jié)構(gòu)體、聯(lián)合體及枚舉類型等三種新的構(gòu)造型數(shù)據(jù)類型以及位運算的基本方 法,包括結(jié)構(gòu)體的含義;結(jié)構(gòu)體類型變量的定義、引用及初始化方法;結(jié)構(gòu)體數(shù)組的定義 和數(shù)組元素的引用;結(jié)構(gòu)體類型指針的概念及鏈表的基本操作方法;聯(lián)合體的含義;聯(lián)合 體類型變量的定義方法;枚舉類型的定義;TYP EDEF的作用和位運算的基本方法等。11.1結(jié)構(gòu)體類型通過前面有關(guān)章節(jié)的學(xué)習(xí),我們認識了整型、實型、字符型等C語言的基本數(shù)據(jù)類型,也了解了數(shù)組這樣一種構(gòu)造型的數(shù)據(jù)結(jié)構(gòu),它可以包含一組同一類型的元素。但僅有這些 數(shù)據(jù)類型是不夠的。在實際問題中,有時需要將不同類型的數(shù)據(jù)組合成一個有機的整體,

2、 以便于引用。例如,在新生入學(xué)登記表中,一個學(xué)生的學(xué)號、姓名、性別、年齡、總分等, 它們屬于同一個處理對象,卻又具有不同的數(shù)據(jù)類型。如圖11-1。每增加、刪減或查閱一個學(xué)生記錄,都需要處理這個學(xué)生的學(xué)號、姓名、性別、年齡、總分等數(shù)據(jù),因此,有必 要把一個學(xué)生的這些數(shù)據(jù)定義成一個整體。學(xué)號姓名性另U年齡總分(整型)(字符型)(字符型)(整型)(實型)11301Zhang P ingF19496.5圖 11-1雖然數(shù)組作為一個整體可用來處理一組相關(guān)的數(shù)據(jù),但不足的是,一個數(shù)組只能按序 組織一批相同類型的數(shù)據(jù)。對于一組不同類型的數(shù)據(jù),顯然不能用一個數(shù)組來存放,因為 數(shù)組中各元素的類型和長度都必須一致

3、。為了解決這個問題,C語言中給出了另一種構(gòu)造 數(shù)據(jù)類型一一“結(jié)構(gòu)體”。11.1.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量結(jié)構(gòu)體是一種構(gòu)造類型,它由若干“成員”組成。每一個成員可以是一個基本數(shù)據(jù)類 型或者又是一個構(gòu)造類型。結(jié)構(gòu)體既然是一種構(gòu)造而成的數(shù)據(jù)類型,那么在使用之前必須 先定義它,如同在調(diào)用函數(shù)之前要先定義或聲明一樣。定義一個結(jié)構(gòu)體類型的一般形式為:struct 結(jié)構(gòu)體名成員1成員2類型1;類型2;成員n類型n;“結(jié)構(gòu)體”這個詞是根據(jù)英文單詞structure 譯出的。結(jié)構(gòu)體中的每個成員均須作類型說明,成員名的命名應(yīng)符合標識符的書寫規(guī)定,成員名可以與程序中的變量名同名,二者不 代表同一對象,互不干擾。3例

4、如:tnum;/*學(xué)號*/charname20 ;/*姓名*/charsex ;/*性別*/intage;/*年齡*/floatscore ;/*成績*/struct student;在上述定義中, struct student 使用中都不能省略。該結(jié)構(gòu)體由 5是結(jié)構(gòu)體類型名,其中 struct 是關(guān)鍵字,在定義和個成員組成。第一個成員為num整型變量,當(dāng)然,在字符數(shù)組;第三個成員 實型變量。應(yīng)注意末尾實際應(yīng)用中我們也常常把學(xué)號定義為字符型;第二個成員為為sex,字符型;第四個成員為age,整型;第五個成員為 score ,的分號是必不可少的。name,數(shù)據(jù)類型和變量是兩個不同的概念。 有了一

5、種結(jié)構(gòu)體類型之后, 就象用 int 去定義一個整型變量那樣。定義結(jié)構(gòu)體類型的變量有以下三種方法。就可用它去定義變量,1. 先定義結(jié)構(gòu)體類型,再定義變量。 例如:intnum;charname20 ;charsex ;intage;floatscore ;struct student;struct student student1,student2本例中, 在定義了 struct student 這個結(jié)構(gòu)體類型之后, 再用這個類型標識符去定義 了兩個結(jié)構(gòu)體變量 student1 與 student2 。為了使用方便,也可以在程序開頭定義一個符號常量來表示一個結(jié)構(gòu)體類型。例如上 例可改寫成:#de

6、fine STU struct studentSTU intnum;charname20 ;charsex ;intage;float score ;STU student1,student22. 在定義結(jié)構(gòu)類型的同時定義結(jié)構(gòu)體變量。例如:struct student intnum;charname20 ;charsex ;intage;floatscore ; student1,student2如果需要,下文還可再用這是一種緊湊形式,既定義了類型,同時又定義了變量。struct student 定義其它同類型變量。它的一般形式為: struct 結(jié)構(gòu)體名成員類型1;成員類型2;成員類型n;5

7、變量名表列;3. 直接定義結(jié)構(gòu)體變量。例如:struct intnum;charname20 ;charsex ;intage;floatscore ; student1,student2直接定義了兩個結(jié)構(gòu)體變量 student1與 student2。這種方法省去了結(jié)構(gòu)體名,缺點是若下文再想定義同類型的變量就不便了。與 student2都具有下圖所示的結(jié)構(gòu),其所有的上述三種方法中定義的變量 student1成員都是基本數(shù)據(jù)類型或數(shù)組類型。numnamesexagescore圖 11-2若想將其中的age換成出生日期birthday ,定義成含有年份、月份、日期三個子成員的類型,如圖11-3所示

8、,則需先定義一個struct date日期類型,再用它去定義birthday。 這就形成了嵌套的結(jié)構(gòu)體。numn amebirthdayyearmonthdayScoresex9圖 11-3按圖可給出以下結(jié)構(gòu)定義:struct date int yearint month int daystruct student intnum;charname20;charsex ;struct datebirthday ;float score student1,student2首先定義一個結(jié)構(gòu)體類型 struct date,由month(月)、day(日)、year(年)三個成員 組成。再將它用到str

9、uct student類型的定義中,使其中的成員 birthday 被定義為struct data類型。類型與變量是不同的概念,不要混同。對結(jié)構(gòu)體變量來說,在定義時一般先定義一個 結(jié)構(gòu)體類型,然后定義變量為該類型。只能對變量賦值、存取或運算,而不能對一個類型 賦值、存取或運算。在編譯時,對類型是不分配空間的,只對變量分配空間。11.1.2結(jié)構(gòu)體變量的引用1. 引用結(jié)構(gòu)體變量中的一個成員由于一個結(jié)構(gòu)體變量包含多個成員,要訪問其中的一個成員,必須同時給出這個成員 所屬的變量名以及其中要訪問的成員名本身,引用方式為:結(jié)構(gòu)體變量名.成員名其中的圓點符號稱為成員運算符。對成員變量可以象普通變量一樣進行各

10、種操作。例如,將學(xué)號11301賦給student1中的num應(yīng)寫成以下形式:student1.num=11301 ;將姓名"ZhangPing”通過鍵盤賦給student1中的name應(yīng)寫成:scanf("%s" , &) ;將 student2 中的 score 加 1,然后輸出該值,應(yīng)寫成:student2.score=student2.score+1或 student2.score+printf("%f" , student2.score)成員運算符的運算級別最高,例如:student.num+100,在

11、num兩側(cè)有二個運算符,由于成員運算符的運算優(yōu)先于加號運算符,故相當(dāng)于2. 成員本身又是結(jié)構(gòu)體類型時的子成員的訪問(student.num)+100如果成員本身又是一種結(jié)構(gòu)體類型時, 那么對其下級子成員再通過成員運算符去訪問, 一級一級地直到最后一級成員為止。例如上文提到的birthday ,可以這樣去訪問:student1.numstudent1.birthday.yearstudent1.birthday.monthstudent1.birthday.daystudent1.score這里, student1.birthday本身相當(dāng)于一個結(jié)構(gòu)體變量。注意下述用法是錯誤的:year/*少了

12、上兩級所屬主體 */birthday.year/*少了結(jié)構(gòu)體變量主體 */student1.year/*不能跨級訪問 */year.birthday.student1/*不能顛倒次序 */3. 同一種類型的結(jié)構(gòu)體變量之間可直接賦值般地,可以將一個結(jié)構(gòu)體變量作為一個整體賦給另一個具有相同類型的結(jié)構(gòu)體變量。例如:student2=student1student1 與 student2 兩者類型相同, 上述賦值語句相當(dāng)于將 student1 中各個成員的值逐 個依次賦給 student2 中的相應(yīng)成員。若兩者的類型不一致時,則不能直接賦值。通常,也可以把一個結(jié)構(gòu)體變量中的內(nèi)嵌結(jié)構(gòu)體類型成員賦給同種類

13、型的另一個結(jié)構(gòu) 體變量的相應(yīng)部分。如下列語句是合法的:student2.birthday=student1.birthday4. 不允許將一個結(jié)構(gòu)體變量作為一個整體進行輸入或輸出下述用法是錯誤的:scanf("%d,%s,%c,%d,%f" , &student1) ;/*錯*/printf(" %d",student1) ;/*錯*/printf("%d,%s,%c,%d,%f" ,student1) ;/*錯*/5. 一個結(jié)構(gòu)體變量所占用的存儲空間就是其所有成員所占空間之和。11.1.3 結(jié)構(gòu)體變量的初始化與其他類型變量一

14、樣,對結(jié)構(gòu)體變量也可以在定義時進行初始化賦值,但附在變量后面的一組數(shù)據(jù)須用花括號括起來,其順序應(yīng)與結(jié)構(gòu)體中的成員順序保持一致?!纠?11-1 】對結(jié)構(gòu)體變量初始化。main() struct student intnum ;charname20 ;charsexintage ;floatscore student1 =11301,"Zhang Ping" , 'F' ,19,496.5 ;printf("Number=%dnName=%sn",student1.num,) printf("Score=%

15、fn",student1.score)運行結(jié)果如下:Number=11301Name=Zhang PingScore=496.500000本例中, student1 在被定義的同時,其各成員也按順序被賦予了相應(yīng)的一組數(shù)據(jù)。11.2 結(jié)構(gòu)體數(shù)組一個結(jié)構(gòu)體變量只能存放一個對象(如一個學(xué)生、一個職工)的一組數(shù)據(jù)。如果要存放一個班(30人)學(xué)生的有關(guān)數(shù)據(jù)就要設(shè)30個結(jié)構(gòu)體變量,例如student1 , student2 ,student30,顯然是不方便的。人們自然想到使用數(shù)組。C語言允許使用結(jié)構(gòu)體數(shù)組,即數(shù)組中每一個元素都是一個結(jié)構(gòu)體變量。11.2.1 結(jié)構(gòu)體數(shù)組的定義定義結(jié)構(gòu)體數(shù)組的方法

16、與定義結(jié)構(gòu)體變量方法相似,只是要多用一個方括弧以說明它是個數(shù)組。在上一節(jié)中定義結(jié)構(gòu)體變量的三種方法可以作為定義結(jié)構(gòu)體數(shù)組的參考。如:struct student intnum;charname20;charsex ;intage ;floatscore ;以上定義了一個結(jié)構(gòu)體變量stude nt1每一個元素都是struct stude nt類型的,和一個結(jié)構(gòu)體數(shù)組 stu,這個數(shù)組有30個元素,如圖11-4所示。數(shù)組各元素在內(nèi)存中占用連續(xù) student1,stu30的一段存儲單元。stu0stu1stu2911301Zhang P ingF19496.511302Wang LiF204831

17、1330Mao QiangM18502numnamesexagescore圖 11-4結(jié)構(gòu)體數(shù)組定義之后,要引用某一元素中的一個成員,可采用以下形式:stui.score式中i為數(shù)組元素的下標。11.2.2結(jié)構(gòu)體數(shù)組的初始化只有對定義為外部的或靜態(tài)的數(shù)組才能初始化。在對結(jié)構(gòu)體變量初始化時,要將每個 元素的數(shù)據(jù)分別用花括弧括起來?!纠?1-2】設(shè)有四位同學(xué)的有關(guān)數(shù)據(jù),試統(tǒng)計出他們的平均年齡和平均成績。 intnum;charname20;charsex ;intage ;floatscore ;struct student stu4= 11301,"Zhang Ping"11

18、302,"Wang Li ",'F',20,483,11303,11304,"Song Rui",'M',19, 471.5;main() int i:>float a,s ;7struct student,'F',19, 496.5 ,"Liu Hong" ,M',19,503, a=a+stui.age, a/4) ;,s/4) ;s=s+stui.scoreprintf("The average age is %6.2fn" printf(&quo

19、t;The average score is %6.2fn"運行結(jié)果如下:The average age is 19.25The average score is 488.5011.3 結(jié)構(gòu)體指針變量通常,可以定義一個指針變量用來指向一個結(jié)構(gòu)體變量,這就是結(jié)構(gòu)體指針變量。結(jié)構(gòu)體指針變量的值就是所指結(jié)構(gòu)體變量在內(nèi)存單元中的起始地址。指針變量也可用來指向結(jié)構(gòu)體數(shù)組中的元素。11.3.1 結(jié)構(gòu)體指針變量定義結(jié)構(gòu)體指針變量的一般形式如下:struct student *p上述語句定義了一個指針變量P,它可以指向任何一個屬于struct student類型的數(shù)據(jù)。通過指針去訪問所指結(jié)構(gòu)體變量的

20、某個成員時,有如下兩種方法:(*p).score或者p->score后者是常見的一種使用方式,其中-稱為指向運算符。student 1q+1q+2stu11302-訓(xùn)肚F2048311303-Llu"'M*1950311304攀皿fTVT19471.5卜就uQstu2圖 llBS 11-5【例11-3】用指針訪問結(jié)構(gòu)體變量及結(jié)構(gòu)體數(shù)組struct student intnum;charname20;charsex;intage;floatscore;;struct student stu3=11302,"Wang",'F',20,48

21、3,11303,"Liu",'M',19,503,11304,"Song",'M',19,471.5;main() struct student student仁11301,"Zhang P ing",'F',19,496.5,* p,*q;int i;p=&student1;/*讓指針p指向結(jié)構(gòu)體變量 student1 ,如圖11-5所示*/p rintf("%s,%c,%5.1fn",,(* p).sex, p->score

22、);q=stu; /*讓指針p指向數(shù)組stu,即指向數(shù)組中的第一個元素stu0,如圖11-6所示*/ for ( i=0;i<3;i+,q+) printf("%s,%c,%5.1fn",q->name,q->sex,q->score);運行結(jié)果如下:Zhang P ing,F,496.5Wang,F,483.013 struct student *p;Song,M,471.5指針符號“ -> ”的使用比較常見。請分析以下幾種運算:p->agep->age+p->age(p+)->age(+p)->age例如,【例

23、 11-3 】中的得到p指向的結(jié)構(gòu)體變量中的成員age的值;先引用 p 所指成員 age 的值,用完后再使該成員值加 1; 先使 p 所指成員 age 的值加 1,然后再引用這個新值; 先引用 p->age 的值,用完后再使指針 p 加 1; 先使指針 p 加 1,然后再引用 p->age 這個值; for 語句:for ( i=0;i<3;i+,q+)printf("%s,%c,%5.1fn",q->name,q->sex,q->score);可改寫為:for ( i=0;i<3;i+)printf("%s,%c,%5.

24、1fn",q->name,q->sex,(q+)->score);11.3.2 用結(jié)構(gòu)體變量和結(jié)構(gòu)體指針變量作函數(shù)參數(shù)結(jié)構(gòu)體變量以及結(jié)構(gòu)體指針變量均可以象 int 類型那樣作為函數(shù)的參數(shù),甚至可以把一個函數(shù)定義成結(jié)構(gòu)體型或結(jié)構(gòu)體指針型。例 11-4 】對年齡在 19 歲以下(含 19 歲)同學(xué)的成績增加 10 分。struct student intnum;charname20;charsex;intage;floatscore;struct student stu3=11302,"Wang",'F',20,483,11303,&

25、quot;Liu",'M',19,503,11304,"Song",'M',19,471.5;void print(struct student s) printf("%s,%d,%5.1fn",,s.age,s.score);void add10(struct student *q) if (q->age<=19)q->score=q->score+10;main()int i;for (i=0;i<3;i+)print(stui);/* 調(diào)用 print 函數(shù) */f

26、or (i=0,p=stu;i<3;i+,p+)add10(p);/*調(diào)用addlO函數(shù)*/printf("n");for (i=O,p=stu;i<3;i+,p+) print(*p);運行結(jié)果如下:Wang,2O,483.OLiu,19,5O3.OSong,19,471.5Wang,2O,483.OLiu,19,513.OSong,19,481.5本例中,函數(shù)print中的形參S,屬于struct student結(jié)構(gòu)體類型,與調(diào)用語句中的實參stui或*p的類型一致;函數(shù) addlO中的形參q,屬于struct student結(jié)構(gòu)體指針類型,與調(diào)用語句中實參

27、P指針的類型一致?!纠?11-5 】將上例中的函數(shù) add1O 改寫成一個返回結(jié)構(gòu)體類型值的函數(shù)struct student add1O(struct student *q) if (q->age<=19)q->score=q->score+1O;return *q;相應(yīng)地,在主函數(shù) main 中的調(diào)用語句也須改為:for (i=O,p=stu;i<3;i+,p+)*p=add1O(p);11.4鏈表11.4.1鏈表概述通過前面有關(guān)章節(jié)的學(xué)習(xí),我們知道, 用數(shù)組存放數(shù)據(jù)時, 必須事先定義固定的長度。15比如 a1OO 最多可以存放 1OO 個數(shù)組元素,多一個都不行

28、。如果待處理的數(shù)據(jù)個數(shù)較多,事先難以確定數(shù)組的大小時,我們只能把這個數(shù)組定義得足夠大,以存放任何可能具有的 數(shù)據(jù)。由于數(shù)組的大小與其占用的內(nèi)存空間成正比,因此,在這種情況下內(nèi)存浪費現(xiàn)象將 比較嚴重。為此,我們需要一種新的數(shù)據(jù)結(jié)構(gòu):當(dāng)數(shù)據(jù)每增加一個時,可以向系統(tǒng)申請空 間從中增加一個元素;當(dāng)數(shù)據(jù)每減少一個時,可以刪除一個元素,釋放其所占內(nèi)存空間。 也就是能夠進行動態(tài)存儲分配,這就是鏈表。鏈表是一種常見的重要的數(shù)據(jù)結(jié)構(gòu)。head110113063148圖 11-719鏈表中的每個元素稱為結(jié)點,一個鏈表由若干結(jié)點組成。圖11-7是一種簡單的單向鏈 表。鏈表中的每個結(jié)點都應(yīng)包括兩部分:其一是數(shù)據(jù)區(qū),存

29、放本結(jié)點要存儲的數(shù)據(jù),其二 是指針區(qū),存放下一個結(jié)點的首地址。因此,鏈表中的每個結(jié)點在內(nèi)存中可以是不連續(xù)的。訪問鏈表時,通過第一個結(jié)點,可以找到第二個結(jié)點;通過第二個結(jié)點,又可以找到第三 個結(jié)點;直到最后一個結(jié)點為止。鏈表的第一個結(jié)點稱為頭結(jié)點,最后一個結(jié)點稱為 尾結(jié)點。鏈表的這種數(shù)據(jù)結(jié)構(gòu)只能利用指針變量才能實現(xiàn)。指向頭結(jié)點的指針變量稱為鏈 表的頭指針,圖11-7中以head表示。尾結(jié)點因無需指向其它結(jié)點,通常將其指針區(qū)賦值 為空值NULL以便判斷。11.4.2處理鏈表的函數(shù)在對鏈表進行動態(tài)管理時,需要用到如下的幾個函數(shù)。:1. 分配內(nèi)存空間函數(shù) malloc調(diào)用形式:(類型說明符*) mal

30、loc(size)功能:在內(nèi)存的動態(tài)存儲區(qū)中分配一塊長度為size個字節(jié)的連續(xù)區(qū)域。函數(shù)的返回值“(類型說明符*) ”表示把返回值為該區(qū)域的首地址。“類型說明符”表示指定該區(qū)域用于何種數(shù)據(jù)類型, 強制轉(zhuǎn)換為該類型指針,“ size ”用于指定空間大小。例如:pc=(char *)malloc(100);pc。表示分配100個字節(jié)的內(nèi)存空間,并強制轉(zhuǎn)換為字符數(shù)組類型,函數(shù)的返回值為指向該字 符數(shù)組的首地址,上述語句把該地址賦予指針變量2. 分配內(nèi)存空間函數(shù) calloccalloc 也用于分配內(nèi)存空間。調(diào)用形式:(類型說明符 *)calloc(n,size)功能:在內(nèi)存動態(tài)存儲區(qū)中分配n塊長度為

31、“ size ”字節(jié)的連續(xù)區(qū)域。函數(shù)的返回值 為該區(qū)域的首地址。calloc 函數(shù)與 malloc 函數(shù)的區(qū)別僅在于一次可以分配 n 塊區(qū)域。3. 釋放內(nèi)存空間函數(shù) free調(diào)用形式:free( 指針變量 ptr) ;功能:釋放 ptr 所指向的一塊內(nèi)存空間, ptr 是一個任意類型的指針變量,它指向被 釋放區(qū)域的首地址。被釋放區(qū)應(yīng)是由 malloc 或 calloc 函數(shù)所分配的區(qū)域。除了上述三個函數(shù)外,另有一個雖與鏈表沒有直接關(guān)系,但在創(chuàng)建結(jié)點中經(jīng)常用到的 函數(shù) sizeof ,它用于測試某種數(shù)據(jù)類型的寬度, 也就是這種類型的數(shù)據(jù)在內(nèi)存中所占用的 字節(jié)數(shù)。例如:float a;printf

32、("%d",sizeof(char);printf("%d",sizeof(a);結(jié)果為 1和 4,因為一個字符型數(shù)據(jù)只需占用一個字節(jié),一個實型變量占四個字節(jié)。ANSI C 標準要求在使用動態(tài)分配函數(shù)時要用#include 命令將 stdlib.h 文件包含進來。11.4.3 鏈表的建立要建立鏈表,必須先定義結(jié)點的數(shù)據(jù)類型。前面介紹的結(jié)構(gòu)體變量,包含若干成員。 這些成員可以是數(shù)值類型、字符類型、數(shù)組類型,也可以是指針類型。這個指針類型可以 指向其它結(jié)構(gòu)體類型,也可以指向自身所在的結(jié)構(gòu)體類型。鏈表中結(jié)點的數(shù)據(jù)類型正是根 據(jù)后面這個思路來定義的。如:intn

33、um;charname20;charsex;intage;floatscore;struct student *link;struct student;link 是成員名,屬于指針類型,它指向 struct student 類型數(shù)據(jù),用于存放下一個同類 型結(jié)點的首地址。 link 成員給鏈表中各個結(jié)點的連接提供了可能。比如,現(xiàn)有兩個指針 P、q,分別指著兩個獨立結(jié)點,另有一個結(jié)構(gòu)體變量stud,通過如下程序片段就可將它們串成一個鏈表,如圖 11-8 所示。圖 11-8struct student *head,* p,*q, stud;p=(struct student *)malloc(siz

34、eof(struct student);/*創(chuàng)建第一個結(jié)點,P指向它*/p->n um=1; p->score=483;/*將數(shù)據(jù)置入該結(jié)點中*/q=(struct student *)malloc(sizeof(struct student);/*創(chuàng)建第二個結(jié)點,q指向它*/q->num=2; q->score=503;stud.num=3; stud.score=471;head=p;/*設(shè)head指向第一個結(jié)點,作為頭指針*/p->link=q;/*在p所指結(jié)點的后面接上第二個結(jié)點*/q->link=&stud;/*在q所指結(jié)點的后面接上變量s

35、tud所表示的結(jié)點*/stud.link=NULL;/*設(shè)置空指針,尾結(jié)點不再指向其它結(jié)點*/注意最后兩句,stud是一個結(jié)構(gòu)體變量,引用時與指針變量是有區(qū)別的。【例11-6】以-1作為結(jié)束標志,編寫一個創(chuàng)建鏈表的函數(shù)#define NULL 0#include "stdlib.h"struct student intnum;/*學(xué)號*/floatscore;/*成績*/struct student *link; /*指向下一個結(jié)點的指針*/;struct student *creat() struct student *head,* p,*q;int number;hea

36、d=NULL;/*初始為空鏈表,沒有任何結(jié)點*/scanf("%d",&number); /*事先讀入一個學(xué)號*/while (number!=-1) /*若不是結(jié)束標志-1,則通過以下循環(huán)創(chuàng)建一個結(jié)點*/ q=(struct student *)malloc(sizeof(struct student); /*申請一個新的結(jié)點*/q->num=number;/*將先前讀入的學(xué)號放入到該結(jié)點中*/scanf("%f", &q->score); /*再讀入該結(jié)點的其他數(shù)據(jù)*/if (head=NULL)/*剛才新建的是不是第一個

37、結(jié)點 */21head=q;/*是,則令該結(jié)點為頭結(jié)點 ,head 為頭指針 */elsep->link=q;/*否, 則將該結(jié)點掛到鏈表尾部 */p=q;/*p總是指向已建鏈表的最后一個結(jié)點 */scanf("%d",&number);/*讀入下一個學(xué)號 */if (head!=NULL)p->link=NULL; /*如果鏈表不為空 , 則設(shè)立尾結(jié)點標志 */return(head);/*返回新建鏈表的頭指針 */struct類型的creat 函數(shù)用于建立一個新的鏈表,它是一個指針函數(shù),它返回的指針屬于student 類型,指向新鏈表的頭結(jié)點。在 C

38、reat 函數(shù)內(nèi)定義了三個 struCt student 指針變量,其中head作為頭指針,總是指向第一個結(jié)點;每次在表尾添入一個結(jié)點后,總是用來指向最新的尾結(jié)點; q 用來申請新的結(jié)點。11.4.4 鏈表的遍歷相對于鏈表的創(chuàng)建而言,鏈表的遍歷,也就是對鏈表的每一個結(jié)點訪問一遍,是比較容易的。遍歷一個鏈表的技術(shù)要點有三:一是要從頭結(jié)點開始,因為單向鏈表反向訪問是不便的;二是每訪問一個結(jié)點前,必須先判空,防止過了表尾;三是當(dāng)前結(jié)點訪問后,需令指向當(dāng)前結(jié)點的指針指向下一個結(jié)點,以利程序循環(huán)操作。例 11-7 】編寫一個遍歷鏈表的函數(shù)。void print(struct student *phead

39、)/*要求將一個鏈表的頭指針作為參數(shù)傳入 */ struct student *p;p=phead;/*從頭結(jié)點開始 */while (p!=NULL)/*當(dāng)前結(jié)點若不為空,則繼續(xù)訪問*/ printf("%d,%5.1fn",p->num ,p->score );p=p->link ;/*指向下一個結(jié)點 */main() print(creat();/* 先調(diào)用函數(shù)creat ,其返回值作為頭指針再傳給函數(shù) print */將【例 11-6 】與【例 11-7 】的程序段合在一起,便是一個完整的鏈表輸入輸出程序。11.4.5 鏈表的插入操作鏈表的插入操作

40、就是將新的結(jié)點插入到一個現(xiàn)有的鏈表中。插入的基本思想是:如果要在原來相鄰的兩個結(jié)點a和b之間插入一個新的結(jié)點C,則需把結(jié)點a中的指針指向C,把結(jié)點C中的指針指向b,這樣就由原來的a7b鏈變成了 af C7b,而排在a之前的結(jié)點與b之后的結(jié)點都不受影響。插入操作可分為四種情形:在一個空鏈表中插入;插在一個鏈表的頭結(jié)點之前;插在兩個結(jié)點之間;插在尾結(jié)點之后。前兩種情形插入后需要改變鏈表的頭指針。圖11-9(a)為插入前的情形;圖 11-9(b)為插入在頭結(jié)點之前的結(jié)果;圖 11-9(c)為插入在兩個結(jié)點之間的結(jié)果。圖 11-9(a)圖11-9(b)圖 11-9(c)由圖11-9 (a)到圖11-9

41、 (b)的變化,可通過如下兩條語句實現(xiàn):P 0->link=head;head=p0;注意,這兩條語句的前后次序不能顛倒。因為一旦先失去了 head中原先的值,就再也這根沒法將原先head所引導(dǎo)的鏈表接回來了。 好比您要將手中正在放著的風(fēng)箏交給別人,牽著的線,是等到別人接上手之后您再松手,還是您先松手了然后別人再過來接?同理,由圖11-9(a)到圖11-9 (C)的變化,可通過如下語句實現(xiàn):p=p->link;p0->link=p->link;p->link=p0;先通過一條或多條 p=p->li nk 這類語句,向后逐步尋找插入點,然后再實施有關(guān)的鏈接操作

42、。【例11-8】寫一個插入函數(shù),在一個有序的鏈表中插入一個結(jié)點,要求插入后的鏈表依然有序。本例中,以學(xué)號為關(guān)鍵字確定各結(jié)點的前后順序。struct student *insert(struct student *p head,struct student *p0) struct student *p ,*q;在空鏈表中插入*/if (p head=NULL ) p head=p0; p0->link=NULL;/*else q=NULL; p=p head;/*從頭結(jié)點開始往后一步一步尋找插入點*/23while( p0->num>=p->num &&

43、p->link !=NULL) q=p; P=P->link; /*q指向當(dāng)前結(jié)點,p指向下一個結(jié)點*/if (q=NULL) p0->link=phead; phead=p0; /*插到首結(jié)點之前 */else if (p0->num<p->num)/*插到q與p所指向的結(jié)點之間*/* 插到尾結(jié)點之后 */ p0->link=p; q->link=p0; else p->link=p0; p0->link=NULL;return(phead);11.4.6 鏈表的刪除操作鏈表的刪除操作就是刪除現(xiàn)有鏈表中的某個結(jié)點。刪除的基本思想是:

44、如果原來的鏈接關(guān)系是af bf c,要把b結(jié)點刪除,則需把結(jié)點a中的指針指向C,把結(jié)點b所占的內(nèi)存空間釋放,這樣就由原來的af bf c鏈變成了 af c,而排在a之前的結(jié)點與c之后的結(jié)點都不受影響。刪除一個結(jié)點時,需要使用free 函數(shù)釋放其所占空間。25刪除操作可分四種情形:對一個空鏈表操作;要刪除的是鏈表的頭結(jié)點,這種情形需要改變鏈表的頭指針;刪除其它的結(jié)點,鏈表的頭指針不動;擬刪除的結(jié)點在鏈表中不存在。例 11-9 】寫一個刪除函數(shù),刪除鏈表中指定學(xué)號所在的結(jié)點。并結(jié)合創(chuàng)建函數(shù)、遍歷函數(shù)、插入函數(shù)的調(diào)用,給出一個main 主函數(shù)。struct student *del(struct s

45、tudent *phead,int num0) struct student *p,*q;p=phead;if (phead=NULL)/*是不是一個空鏈表 ?*/return(phead);else if (phead->num=num0)phead=phead->link;/*要刪除的是頭結(jié)點 , 把下一個結(jié)點作為新的頭結(jié)點 */else while(p->num!=num0 ) /*根據(jù)關(guān)鍵字num0查找結(jié)點*/ q=p; p=p->link; /* q指向當(dāng)前結(jié)點,P指向下一個結(jié)點*/if (p=NULL) break; /*查找完畢,不再查找 */*循環(huán)完成后

46、, p 指向要刪除的結(jié)點 */if (p!=NULL)q->link=p->link;/*刪除 p 所指向的結(jié)點 */elsereturn(phead);/*未找到要刪除的結(jié)點 */if (p!=NULL) free(p);/*釋放空間 */after delete:main() struct student *head,*newnode;int num;head=creat();/* 創(chuàng)建一個鏈表 */printf("before insert:n");print(head);/* 在插入前輸出鏈表 */printf("input the inser

47、ted record:");newnode=(struct student *)malloc(sizeof(struct student);scanf("%d,%f",&newnode->num,&newnode->score);head=insert(head,newnode);/*插入一個結(jié)點 */27printf("after insert:n");print(head);/*在插入后輸出鏈表 */printf("input the num to delete:");scanf("

48、%d",&num);head=del(head,num);/*刪除鏈表中的一個結(jié)點 */printf("after delete:n");print(head);/*在刪除一個結(jié)后再輸出鏈表 */說明:完整的程序由例 11-6 中的結(jié)點類型定義與 creat 創(chuàng)建鏈表函數(shù)、例 11-7 中的print 遍歷函數(shù)、 例 11-8 中的 insert 插入函數(shù)以及上述 del 刪除函數(shù)與 main 主函數(shù)組成。程序運行情況如下,其中“ -1,-1 ”這一行之前的數(shù)據(jù)由鍵盤輸入。23,483 /31,501 /35,493 /-1,-1 /before inse

49、rt: 23,483.0 31,501.0 35,493.0 input the inserted record:27,450 after insert: 23,483.0 27,450.0 31,501.0 35,493.0 input the num to delete:3123,483.027,450.035,493.011.5 聯(lián) 合 體11.5.1聯(lián)合體類型定義所謂聯(lián)合體數(shù)據(jù)類型是指將不同的數(shù)據(jù)項存放于同一段內(nèi)存單元的一種構(gòu)造數(shù)據(jù)類型。同結(jié)構(gòu)體類型相似,在一個聯(lián)合體內(nèi)可以定義多種不同的數(shù)據(jù)類型;不同的是,在一 個聯(lián)合體類型的變量中,其所有成員共用同一塊內(nèi)存單元,因此,雖然每一個成員均

50、可以 被賦值,但只有最后一次賦進去的成員值能夠保存下來,而先前賦進去的那些成員值均被 后來的覆蓋了。定義一個聯(lián)合體類型的一般形式為:union 聯(lián)合體名成員 1類型 1;成員 2類型 2;成員 n類型 n;例如:union data inta;floatb;charc;union datax,y;也可以將類型定義與變量定義合在一起:union data int a;float b;char c; x,y;聯(lián)合體與結(jié)構(gòu)體雖形式相似,但含義有別。一個結(jié)構(gòu)體變量所占內(nèi)存長度是各成員占 的內(nèi)存長度之和,每個成員分別占有自己的內(nèi)存單元;而一個聯(lián)合體變量所占內(nèi)存長度等 于其所有成員中最長的成員的長度,所有

51、成員共用一段內(nèi)存單元,所以,有的地方也把聯(lián)合體稱為共用體。11.5.2聯(lián)合體變量的引用對聯(lián)合體變量的賦值、使用都只能是對變量的成員進行。聯(lián)合體變量的成員表示為:聯(lián)合變量名 . 成員名例如,對于上文定義的變量 x與y,可使用以下三種方式之一訪問成員值。 或者x.ax.b或者y.c在使用聯(lián)合體類型數(shù)據(jù)時應(yīng)注意以下一些特點: 同一內(nèi)存段可以用來存放幾種不同類型的成員,但在每一瞬時只能存放其中一種, 而不是同時存放幾種。也就是說,每一瞬時只有一個成員起作用,其它的成員不起作用, 即不是同時都存在或起作用。 聯(lián)合體變量中起作用的成員是最后一次存放的成員,成員就失去作用。例如,以下幾條賦值語句:在存入一個

52、新的成員后原有的x.a=1;x.b=3.6;x.c= ' H'雖然先后給三個成員賦了值,但只有 x.c 是有效的,而 x.a 與 x.b 已經(jīng)無意義而且也不能 被引用了。 聯(lián)合體變量的地址和它的各成員的地址都是同一地址。 不能對聯(lián)合體變量名賦值, 也不能企圖引用變量名來得到成員的值, 又不能在定義 聯(lián)合體變量時對它初始化。例如,下列語句都是錯誤的:union data int a;float b;char c; x=1,3.6, 'H' ,y;/*錯,不能初始化 */x=1;/*錯,不能對聯(lián)合體變量名賦值 */y=x;/*錯,不能引用聯(lián)合體變量名以得到值 */

53、不能把聯(lián)合體變量作為函數(shù)參數(shù), 也不能把一個函數(shù)的類型定義成聯(lián)合體類型, 可以使用指向聯(lián)合體變量的指針。 聯(lián)合體與結(jié)構(gòu)體可以互相嵌套。 在聯(lián)合體中可以定義結(jié)構(gòu)體成員, 或者也可以在結(jié) 構(gòu)體中定義聯(lián)合體成員?!纠?11-10 】一個學(xué)校的人員數(shù)據(jù)管理中,教師的數(shù)據(jù)包括:編號、姓名、性別、職 務(wù),學(xué)生的數(shù)據(jù)包括:編號、姓名、性別、班號。它們放在同一種表格中,顯然有這么一 欄,或者登記教師的“職務(wù)”,或者登記學(xué)生的“班號”,而不會在這同一欄中同時寫上 這兩項數(shù)據(jù)。試給出類型定義及輸入輸出方法。31編號num姓名name性別sex職業(yè)job班號 class職務(wù) Positionstruct p erson long num;char name20;char sex;char job;union int class;char p osition20;category;p erson10;結(jié)構(gòu)體成員job用作身份標志,如果輸入為s'(學(xué)生),則要對聯(lián)合體成員 category中的class操作,如果輸入為t ,則要對其中的 position 操作。輸入輸出方法為:scanf(" %c",&p erson0.job);if (person0.job=' s')scanf("%d",&p ers

溫馨提示

  • 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論