版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、第11章 結(jié)構(gòu)體、聯(lián)合體與位運(yùn)算本章介紹結(jié)構(gòu)體、聯(lián)合體及枚舉類型等三種新的構(gòu)造型數(shù)據(jù)類型以及位運(yùn)算的基本方法,包括結(jié)構(gòu)體的含義;結(jié)構(gòu)體類型變量的定義、引用及初始化方法;結(jié)構(gòu)體數(shù)組的定義和數(shù)組元素的引用;結(jié)構(gòu)體類型指針的概念及鏈表的基本操作方法;聯(lián)合體的含義;聯(lián)合體類型變量的定義方法;枚舉類型的定義; TYPEDEF的作用和位運(yùn)算的基本方法等。11.1 結(jié)構(gòu)體類型通過前面有關(guān)章節(jié)的學(xué)習(xí),我們認(rèn)識(shí)了整型、實(shí)型、字符型等C語言的基本數(shù)據(jù)類型,也了解了數(shù)組這樣一種構(gòu)造型的數(shù)據(jù)結(jié)構(gòu),它可以包含一組同一類型的元素。但僅有這些數(shù)據(jù)類型是不夠的。在實(shí)際問題中,有時(shí)需要將不同類型的數(shù)據(jù)組合成一個(gè)有機(jī)的整體,以便
2、于引用。例如,在新生入學(xué)登記表中,一個(gè)學(xué)生的學(xué)號(hào)、姓名、性別、年齡、總分等,它們屬于同一個(gè)處理對(duì)象,卻又具有不同的數(shù)據(jù)類型。如圖11-1。每增加、刪減或查閱一個(gè)學(xué)生記錄,都需要處理這個(gè)學(xué)生的學(xué)號(hào)、姓名、性別、年齡、總分等數(shù)據(jù),因此,有必要把一個(gè)學(xué)生的這些數(shù)據(jù)定義成一個(gè)整體。學(xué) 號(hào)(整型)姓 名(字符型)性 別(字符型)年 齡(整型)總 分(實(shí)型)11301Zhang PingF19496.5圖11-1雖然數(shù)組作為一個(gè)整體可用來處理一組相關(guān)的數(shù)據(jù),但不足的是,一個(gè)數(shù)組只能按序組織一批相同類型的數(shù)據(jù)。對(duì)于一組不同類型的數(shù)據(jù),顯然不能用一個(gè)數(shù)組來存放,因?yàn)閿?shù)組中各元素的類型和長度都必須一致。為了解決
3、這個(gè)問題,語言中給出了另一種構(gòu)造數(shù)據(jù)類型“結(jié)構(gòu)體”。 11.1.1 結(jié)構(gòu)體類型與結(jié)構(gòu)體變量結(jié)構(gòu)體是一種構(gòu)造類型,它由若干“成員”組成。每一個(gè)成員可以是一個(gè)基本數(shù)據(jù)類型或者又是一個(gè)構(gòu)造類型。結(jié)構(gòu)體既然是一種構(gòu)造而成的數(shù)據(jù)類型,那么在使用之前必須先定義它,如同在調(diào)用函數(shù)之前要先定義或聲明一樣。定義一個(gè)結(jié)構(gòu)體類型的一般形式為:struct 結(jié)構(gòu)體名 成員1類型1;成員2 類型2;.成員n 類型n;“結(jié)構(gòu)體”這個(gè)詞是根據(jù)英文單詞structure譯出的。結(jié)構(gòu)體中的每個(gè)成員均須作類型說明,成員名的命名應(yīng)符合標(biāo)識(shí)符的書寫規(guī)定,成員名可以與程序中的變量名同名,二者不代表同一對(duì)象,互不干擾。例如:struct
4、 student int num;/* 學(xué)號(hào) */char name20;/* 姓名 */char sex;/* 性別 */int age;/* 年齡 */float score;/* 成績 */;在上述定義中,struct student是結(jié)構(gòu)體類型名,其中struct是關(guān)鍵字,在定義和使用中都不能省略。該結(jié)構(gòu)體由5個(gè)成員組成。第一個(gè)成員為num,整型變量,當(dāng)然,在實(shí)際應(yīng)用中我們也常常把學(xué)號(hào)定義為字符型;第二個(gè)成員為name,字符數(shù)組;第三個(gè)成員為sex,字符型;第四個(gè)成員為age,整型;第五個(gè)成員為score,實(shí)型變量。應(yīng)注意末尾的分號(hào)是必不可少的。數(shù)據(jù)類型和變量是兩個(gè)不同的概念。有了一種
5、結(jié)構(gòu)體類型之后,就可用它去定義變量,就象用int 去定義一個(gè)整型變量那樣。定義結(jié)構(gòu)體類型的變量有以下三種方法。1.先定義結(jié)構(gòu)體類型,再定義變量。例如:struct student int num; char name20; char sex; int age; float score;struct student student1,student2;本例中,在定義了struct student這個(gè)結(jié)構(gòu)體類型之后,再用這個(gè)類型標(biāo)識(shí)符去定義了兩個(gè)結(jié)構(gòu)體變量student1與student2。為了使用方便,也可以在程序開頭定義一個(gè)符號(hào)常量來表示一個(gè)結(jié)構(gòu)體類型。例如上例可改寫成:#define STU
6、 struct student.STU int num; char name20; char sex; int age; float score;STU student1,student2;2.在定義結(jié)構(gòu)類型的同時(shí)定義結(jié)構(gòu)體變量。例如:struct student int num; char name20; char sex; int age; float score; student1,student2;這是一種緊湊形式,既定義了類型,同時(shí)又定義了變量。如果需要,下文還可再用struct student定義其它同類型變量。它的一般形式為:struct 結(jié)構(gòu)體名 成員1類型1;成員2 類型2;
7、.成員n 類型n;變量名表列;3.直接定義結(jié)構(gòu)體變量。例如:struct int num; char name20; char sex; int age; float score; student1,student2;直接定義了兩個(gè)結(jié)構(gòu)體變量student1與student2。這種方法省去了結(jié)構(gòu)體名,缺點(diǎn)是若下文再想定義同類型的變量就不便了。上述三種方法中定義的變量student1與student2都具有下圖所示的結(jié)構(gòu),其所有的成員都是基本數(shù)據(jù)類型或數(shù)組類型。numnamesexagescore圖11-2若想將其中的age換成出生日期birthday,定義成含有年份、月份、日期三個(gè)子成員的類型
8、,如圖11-3所示,則需先定義一個(gè)struct date日期類型,再用它去定義birthday。這就形成了嵌套的結(jié)構(gòu)體。numnamesexbirthdayScoreyearmonthday圖11-3按圖可給出以下結(jié)構(gòu)定義:struct date int year; int month; int day;struct student int num; char name20; char sex; struct date birthday; float score; student1,student2;首先定義一個(gè)結(jié)構(gòu)體類型struct date,由month(月)、day(日)、year(年)
9、 三個(gè)成員組成。 再將它用到struct student類型的定義中,使其中的成員birthday被定義為struct data類型。類型與變量是不同的概念,不要混同。對(duì)結(jié)構(gòu)體變量來說,在定義時(shí)一般先定義一個(gè)結(jié)構(gòu)體類型,然后定義變量為該類型。只能對(duì)變量賦值、存取或運(yùn)算,而不能對(duì)一個(gè)類型賦值、存取或運(yùn)算。在編譯時(shí),對(duì)類型是不分配空間的,只對(duì)變量分配空間。11.1.2 結(jié)構(gòu)體變量的引用1.引用結(jié)構(gòu)體變量中的一個(gè)成員由于一個(gè)結(jié)構(gòu)體變量包含多個(gè)成員,要訪問其中的一個(gè)成員,必須同時(shí)給出這個(gè)成員所屬的變量名以及其中要訪問的成員名本身,引用方式為:結(jié)構(gòu)體變量名.成員名其中的圓點(diǎn)符號(hào)稱為成員運(yùn)算符。對(duì)成員變量
10、可以象普通變量一樣進(jìn)行各種操作。例如,將學(xué)號(hào)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);成員運(yùn)算符的運(yùn)算級(jí)別最高,例如:student.num+100,在num兩側(cè)有二個(gè)運(yùn)算符,由于成員運(yùn)算符的運(yùn)算優(yōu)先于加號(hào)
11、運(yùn)算符,故相當(dāng)于(student.num)+1002.成員本身又是結(jié)構(gòu)體類型時(shí)的子成員的訪問如果成員本身又是一種結(jié)構(gòu)體類型時(shí),那么對(duì)其下級(jí)子成員再通過成員運(yùn)算符去訪問,一級(jí)一級(jí)地直到最后一級(jí)成員為止。例如上文提到的birthday,可以這樣去訪問:student1.numstudent1.score這里,student1.birthday本身相當(dāng)于一個(gè)結(jié)構(gòu)體變量。注意下述用法是錯(cuò)誤的:year /*少了上兩級(jí)所屬主體*/birthday.year/*少了結(jié)構(gòu)體變量主體*/student1.year/*不能跨級(jí)訪問*/year.birthday.student1/*不能顛倒次序*/3.同一種類型
12、的結(jié)構(gòu)體變量之間可直接賦值一般地,可以將一個(gè)結(jié)構(gòu)體變量作為一個(gè)整體賦給另一個(gè)具有相同類型的結(jié)構(gòu)體變量。例如:student2=student1;student1與student2兩者類型相同,上述賦值語句相當(dāng)于將student1中各個(gè)成員的值逐個(gè)依次賦給student2中的相應(yīng)成員。若兩者的類型不一致時(shí),則不能直接賦值。通常,也可以把一個(gè)結(jié)構(gòu)體變量中的內(nèi)嵌結(jié)構(gòu)體類型成員賦給同種類型的另一個(gè)結(jié)構(gòu)體變量的相應(yīng)部分。如下列語句是合法的:student2.birthday=student1.birthday;4.不允許將一個(gè)結(jié)構(gòu)體變量作為一個(gè)整體進(jìn)行輸入或輸出下述用法是錯(cuò)誤的:scanf(%d,%s,
13、%c,%d,%f,&student1);/*錯(cuò)*/printf( %d,student1); /*錯(cuò)*/printf(%d,%s,%c,%d,%f,student1); /*錯(cuò)*/5.一個(gè)結(jié)構(gòu)體變量所占用的存儲(chǔ)空間就是其所有成員所占空間之和。11.1.3 結(jié)構(gòu)體變量的初始化與其他類型變量一樣,對(duì)結(jié)構(gòu)體變量也可以在定義時(shí)進(jìn)行初始化賦值,但附在變量后面的一組數(shù)據(jù)須用花括號(hào)括起來,其順序應(yīng)與結(jié)構(gòu)體中的成員順序保持一致?!纠?1-1】對(duì)結(jié)構(gòu)體變量初始化。main() struct student int num;char name20;char sex;int age;float score; stu
14、dent1 =11301,Zhang Ping,F(xiàn),19,496.5;printf(Number=%dnName=%sn,student1.num,);printf(Score=%fn,student1.score);運(yùn)行結(jié)果如下:Number=11301Name=Zhang PingScore=496.500000本例中,student1在被定義的同時(shí),其各成員也按順序被賦予了相應(yīng)的一組數(shù)據(jù)。11.2 結(jié)構(gòu)體數(shù)組一個(gè)結(jié)構(gòu)體變量只能存放一個(gè)對(duì)象(如一個(gè)學(xué)生、一個(gè)職工)的一組數(shù)據(jù)。如果要存放一個(gè)班(30人)學(xué)生的有關(guān)數(shù)據(jù)就要設(shè)30個(gè)結(jié)構(gòu)體變量,例如student1,st
15、udent2,student30,顯然是不方便的。人們自然想到使用數(shù)組。C語言允許使用結(jié)構(gòu)體數(shù)組,即數(shù)組中每一個(gè)元素都是一個(gè)結(jié)構(gòu)體變量。11.2.1 結(jié)構(gòu)體數(shù)組的定義定義結(jié)構(gòu)體數(shù)組的方法與定義結(jié)構(gòu)體變量方法相似,只是要多用一個(gè)方括弧以說明它是個(gè)數(shù)組。在上一節(jié)中定義結(jié)構(gòu)體變量的三種方法可以作為定義結(jié)構(gòu)體數(shù)組的參考。如:struct student int num; char name20; char sex; int age; float score; student1,stu30;以上定義了一個(gè)結(jié)構(gòu)體變量student1和一個(gè)結(jié)構(gòu)體數(shù)組stu,這個(gè)數(shù)組有30個(gè)元素,每一個(gè)元素都是struct
16、student類型的,如圖11-4所示。數(shù)組各元素在內(nèi)存中占用連續(xù)的一段存儲(chǔ)單元。numnamesexagescorestu011301Zhang PingF19496.5stu111302Wang LiF20483stu2911330Mao QiangM18502圖11-4結(jié)構(gòu)體數(shù)組定義之后,要引用某一元素中的一個(gè)成員,可采用以下形式:stui.score式中i為數(shù)組元素的下標(biāo)。11.2.2 結(jié)構(gòu)體數(shù)組的初始化只有對(duì)定義為外部的或靜態(tài)的數(shù)組才能初始化。在對(duì)結(jié)構(gòu)體變量初始化時(shí),要將每個(gè)元素的數(shù)據(jù)分別用花括弧括起來。【例11-2】設(shè)有四位同學(xué)的有關(guān)數(shù)據(jù),試統(tǒng)計(jì)出他們的平均年齡和平均成績。stru
17、ct student int num; char name20; char sex; int age; float score;struct student stu4= 11301,Zhang Ping,F(xiàn),19,496.5 ,11302, Wang Li ,F(xiàn),20,483,11303,Liu Hong,M,19,503,11304,Song Rui,M,19,471.5;main() int i;float a,s;for (i=0;iscore后者是常見的一種使用方式,其中-稱為指向運(yùn)算符?!纠?1-3】 用指針訪問結(jié)構(gòu)體變量及結(jié)構(gòu)體數(shù)組struct student int num; c
18、har name20; char sex; int age; float score;struct student stu3=11302,Wang,F,20,483,11303,Liu,M,19,503,11304,Song,M,19,471.5;main() struct student student1=11301,Zhang Ping,F,19,496.5,*p,*q;int i;p=&student1;/* 讓指針p指向結(jié)構(gòu)體變量student1 ,如圖11-5所示*/printf(%s,%c,%5.1fn,,(*p).sex,p-score);q=stu;/
19、*讓指針p指向數(shù)組stu,即指向數(shù)組中的第一個(gè)元素stu0,如圖11-6所示 */for ( i=0;iname,q-sex,q-score);運(yùn)行結(jié)果如下:Zhang Ping,F,496.5Wang,F,483.0Liu,M,503.0Song,M,471.5指針符號(hào)“-”的使用比較常見。請(qǐng)分析以下幾種運(yùn)算:p-age得到p指向的結(jié)構(gòu)體變量中的成員age的值;p-age+先引用p所指成員age的值,用完后再使該成員值加1;+p-age先使p所指成員age的值加1,然后再引用這個(gè)新值;(p+)-age先引用p-age的值,用完后再使指針p加1;(+p)-age先使指針p加1,然后再引用p-a
20、ge這個(gè)值;例如,【例11-3】中的for語句:for ( i=0;iname,q-sex,q-score);可改寫為:for ( i=0;iname,q-sex,(q+)-score);11.3.2 用結(jié)構(gòu)體變量和結(jié)構(gòu)體指針變量作函數(shù)參數(shù)結(jié)構(gòu)體變量以及結(jié)構(gòu)體指針變量均可以象int類型那樣作為函數(shù)的參數(shù),甚至可以把一個(gè)函數(shù)定義成結(jié)構(gòu)體型或結(jié)構(gòu)體指針型。【例11-4】對(duì)年齡在19歲以下(含19歲)同學(xué)的成績?cè)黾?0分。struct student int num; char name20; char sex; int age; float score;struct student stu3=11
21、302,Wang,F,20,483,11303,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-agescore=q-score+10;main() struct student *p;int i;for (i=0;i3;i+) print(stui);/*調(diào)用print函數(shù)*/for (i=0,p=stu;i3;i+,p+) add10(p);/*調(diào)用add1
22、0函數(shù)*/printf(n);for (i=0,p=stu;iagescore=q-score+10;return *q;相應(yīng)地,在主函數(shù)main中的調(diào)用語句也須改為:for (i=0,p=stu;inum=1; p-score=483;/*將數(shù)據(jù)置入該結(jié)點(diǎn)中*/q=(struct student *)malloc(sizeof(struct student);/*創(chuàng)建第二個(gè)結(jié)點(diǎn),q指向它*/ q-num=2; q-score=503;stud.num=3; stud.score=471; head=p;/* 設(shè)head指向第一個(gè)結(jié)點(diǎn),作為頭指針 */p-link=q; /* 在p所指結(jié)點(diǎn)的后
23、面接上第二個(gè)結(jié)點(diǎn) */q-link=&stud;/* 在q所指結(jié)點(diǎn)的后面接上變量stud所表示的結(jié)點(diǎn) */stud.link=NULL;/* 設(shè)置空指針,尾結(jié)點(diǎn)不再指向其它結(jié)點(diǎn) */注意最后兩句,stud是一個(gè)結(jié)構(gòu)體變量,引用時(shí)與指針變量是有區(qū)別的?!纠?1-6】以-1作為結(jié)束標(biāo)志,編寫一個(gè)創(chuàng)建鏈表的函數(shù)#define NULL 0#include stdlib.h;struct student int num; /*學(xué)號(hào)*/ float score; /*成績*/ struct student *link; /*指向下一個(gè)結(jié)點(diǎn)的指針*/;struct student *creat() str
24、uct student *head,*p,*q; int number; head=NULL; /*初始為空鏈表,沒有任何結(jié)點(diǎn)*/ scanf(%d,&number); /*事先讀入一個(gè)學(xué)號(hào)*/ while (number!=-1) /* 若不是結(jié)束標(biāo)志-1,則通過以下循環(huán)創(chuàng)建一個(gè)結(jié)點(diǎn)*/ q=(struct student *)malloc(sizeof(struct student); /*申請(qǐng)一個(gè)新的結(jié)點(diǎn)*/ q-num=number; /*將先前讀入的學(xué)號(hào)放入到該結(jié)點(diǎn)中*/ scanf(%f,&q-score); /*再讀入該結(jié)點(diǎn)的其他數(shù)據(jù)*/ if (head=NULL) /*剛才新
25、建的是不是第一個(gè)結(jié)點(diǎn)*/ head=q; /*是,則令該結(jié)點(diǎn)為頭結(jié)點(diǎn),head為頭指針*/ else p-link=q; /*否,則將該結(jié)點(diǎn)掛到鏈表尾部*/ p=q; /*p總是指向已建鏈表的最后一個(gè)結(jié)點(diǎn)*/ scanf(%d,&number); /*讀入下一個(gè)學(xué)號(hào)*/ if (head!=NULL) p-link=NULL; /*如果鏈表不為空,則設(shè)立尾結(jié)點(diǎn)標(biāo)志*/ return(head); /*返回新建鏈表的頭指針*/ creat函數(shù)用于建立一個(gè)新的鏈表,它是一個(gè)指針函數(shù),它返回的指針屬于struct student類型,指向新鏈表的頭結(jié)點(diǎn)。在creat函數(shù)內(nèi)定義了三個(gè)struct st
26、udent類型的指針變量,其中head作為頭指針,總是指向第一個(gè)結(jié)點(diǎn);每次在表尾添入一個(gè)結(jié)點(diǎn)后,p總是用來指向最新的尾結(jié)點(diǎn);q用來申請(qǐng)新的結(jié)點(diǎn)。11.4.4 鏈表的遍歷相對(duì)于鏈表的創(chuàng)建而言,鏈表的遍歷,也就是對(duì)鏈表的每一個(gè)結(jié)點(diǎn)訪問一遍,是比較容易的。遍歷一個(gè)鏈表的技術(shù)要點(diǎn)有三:一是要從頭結(jié)點(diǎn)開始,因?yàn)閱蜗蜴湵矸聪蛟L問是不便的;二是每訪問一個(gè)結(jié)點(diǎn)前,必須先判空,防止過了表尾;三是當(dāng)前結(jié)點(diǎn)訪問后,需令指向當(dāng)前結(jié)點(diǎn)的指針指向下一個(gè)結(jié)點(diǎn),以利程序循環(huán)操作?!纠?1-7】編寫一個(gè)遍歷鏈表的函數(shù)。void print(struct student *phead)/*要求將一個(gè)鏈表的頭指針作為參數(shù)傳入*/
27、struct student *p; p=phead;/*從頭結(jié)點(diǎn)開始*/ while (p!=NULL)/*當(dāng)前結(jié)點(diǎn)若不為空,則繼續(xù)訪問*/ printf(%d,%5.1fn,p-num ,p-score ); p=p-link ;/*指向下一個(gè)結(jié)點(diǎn)*/ main() print(creat();/*先調(diào)用函數(shù)creat,其返回值作為頭指針再傳給函數(shù)print */將【例11-6】與【例11-7】的程序段合在一起,便是一個(gè)完整的鏈表輸入輸出程序。11.4.5 鏈表的插入操作鏈表的插入操作就是將新的結(jié)點(diǎn)插入到一個(gè)現(xiàn)有的鏈表中。插入的基本思想是:如果要在原來相鄰的兩個(gè)結(jié)點(diǎn)a和b之間插入一個(gè)新的結(jié)
28、點(diǎn)c,則需把結(jié)點(diǎn)a中的指針指向c,把結(jié)點(diǎn)c中的指針指向b,這樣就由原來的ab鏈變成了acb,而排在a之前的結(jié)點(diǎn)與b之后的結(jié)點(diǎn)都不受影響。插入操作可分為四種情形: 在一個(gè)空鏈表中插入; 插在一個(gè)鏈表的頭結(jié)點(diǎn)之前; 插在兩個(gè)結(jié)點(diǎn)之間; 插在尾結(jié)點(diǎn)之后。前兩種情形插入后需要改變鏈表的頭指針。圖11-9(a)為插入前的情形;圖11-9(b)為插入在頭結(jié)點(diǎn)之前的結(jié)果;圖11-9(c)為插入在兩個(gè)結(jié)點(diǎn)之間的結(jié)果。圖11-9(a)圖11-9(b)圖11-9(c)由圖11-9(a)到圖11-9(b)的變化,可通過如下兩條語句實(shí)現(xiàn):p0-link=head;head=p0;注意,這兩條語句的前后次序不能顛倒。因
29、為一旦先失去了head中原先的值,就再也沒法將原先head所引導(dǎo)的鏈表接回來了。好比您要將手中正在放著的風(fēng)箏交給別人,這根牽著的線,是等到別人接上手之后您再松手,還是您先松手了然后別人再過來接?同理,由圖11-9(a)到圖11-9(c)的變化,可通過如下語句實(shí)現(xiàn):p=p-link;p0-link=p-link;p-link=p0;先通過一條或多條p=p-link這類語句,向后逐步尋找插入點(diǎn),然后再實(shí)施有關(guān)的鏈接操作。【例11-8】寫一個(gè)插入函數(shù),在一個(gè)有序的鏈表中插入一個(gè)結(jié)點(diǎn),要求插入后的鏈表依然有序。本例中,以學(xué)號(hào)為關(guān)鍵字確定各結(jié)點(diǎn)的前后順序。struct student *insert(s
30、truct student *phead,struct student *p0) struct student *p,*q; if (phead=NULL ) phead=p0;p0-link=NULL; /*在空鏈表中插入*/ else q=NULL; p=phead; /*從頭結(jié)點(diǎn)開始往后一步一步尋找插入點(diǎn)*/ while(p0-num=p-num & p-link !=NULL) q=p; p=p-link; /*q指向當(dāng)前結(jié)點(diǎn),p指向下一個(gè)結(jié)點(diǎn) */ if (q=NULL) p0-link=phead; phead=p0; /*插到首結(jié)點(diǎn)之前*/ else if (p0-numnum)
31、 p0-link=p; q-link=p0; /*插到q與p所指向的結(jié)點(diǎn)之間*/ else p-link=p0; p0-link=NULL; /*插到尾結(jié)點(diǎn)之后*/ return(phead);11.4.6 鏈表的刪除操作鏈表的刪除操作就是刪除現(xiàn)有鏈表中的某個(gè)結(jié)點(diǎn)。刪除的基本思想是:如果原來的鏈接關(guān)系是abc,要把b結(jié)點(diǎn)刪除,則需把結(jié)點(diǎn)a中的指針指向c,把結(jié)點(diǎn)b所占的內(nèi)存空間釋放,這樣就由原來的abc鏈變成了ac,而排在a之前的結(jié)點(diǎn)與c之后的結(jié)點(diǎn)都不受影響。刪除一個(gè)結(jié)點(diǎn)時(shí),需要使用free函數(shù)釋放其所占空間。刪除操作可分四種情形: 對(duì)一個(gè)空鏈表操作; 要?jiǎng)h除的是鏈表的頭結(jié)點(diǎn),這種情形需要改變鏈
32、表的頭指針; 刪除其它的結(jié)點(diǎn),鏈表的頭指針不動(dòng); 擬刪除的結(jié)點(diǎn)在鏈表中不存在?!纠?1-9】寫一個(gè)刪除函數(shù),刪除鏈表中指定學(xué)號(hào)所在的結(jié)點(diǎn)。并結(jié)合創(chuàng)建函數(shù)、遍歷函數(shù)、插入函數(shù)的調(diào)用,給出一個(gè)main主函數(shù)。struct student *del(struct student *phead,int num0) struct student *p,*q; p=phead; if (phead=NULL) /*是不是一個(gè)空鏈表?*/ return(phead); else if (phead-num=num0) phead=phead-link; /*要?jiǎng)h除的是頭結(jié)點(diǎn),把下一個(gè)結(jié)點(diǎn)作為新的頭結(jié)點(diǎn)*/
33、else while(p-num!=num0 ) /*根據(jù)關(guān)鍵字num0查找結(jié)點(diǎn)*/ q=p; p=p-link; /* q指向當(dāng)前結(jié)點(diǎn),p指向下一個(gè)結(jié)點(diǎn) */ if (p=NULL) break; /* 查找完畢,不再查找 */ /* 循環(huán)完成后,p指向要?jiǎng)h除的結(jié)點(diǎn) */ if (p!=NULL) q-link=p-link; /*刪除p所指向的結(jié)點(diǎn)*/ else return(phead); /*未找到要?jiǎng)h除的結(jié)點(diǎn)*/ if (p!=NULL) free(p); /*釋放空間*/ return(phead);main() struct student *head,*newnode; int
34、 num; head=creat();/*創(chuàng)建一個(gè)鏈表*/ printf(before insert:n); print(head);/*在插入前輸出鏈表*/ printf(input the inserted record:); newnode=(struct student *)malloc(sizeof(struct student); scanf(%d,%f,&newnode-num,&newnode-score); head=insert(head,newnode);/*插入一個(gè)結(jié)點(diǎn)*/ printf(after insert:n); print(head);/*在插入后輸出鏈表*/
35、 printf(input the num to delete:); scanf(%d,&num); head=del(head,num);/*刪除鏈表中的一個(gè)結(jié)點(diǎn)*/ printf(after delete:n); print(head);/*在刪除一個(gè)結(jié)后再輸出鏈表*/說明:完整的程序由例11-6中的結(jié)點(diǎn)類型定義與creat創(chuàng)建鏈表函數(shù)、例11-7中的print遍歷函數(shù)、例11-8中的insert插入函數(shù)以及上述del刪除函數(shù)與main主函數(shù)組成。程序運(yùn)行情況如下,其中“-1,-1”這一行之前的數(shù)據(jù)由鍵盤輸入。23,48331,50135,493-1,-1before insert:23,
36、483.031,501.035,493.0input the inserted record:27,450after insert:23,483.027,450.031,501.035,493.0input the num to delete:31after delete:23,483.027,450.035,493.011.5 聯(lián) 合 體11.5.1聯(lián)合體類型定義所謂聯(lián)合體數(shù)據(jù)類型是指將不同的數(shù)據(jù)項(xiàng)存放于同一段內(nèi)存單元的一種構(gòu)造數(shù)據(jù)類型。同結(jié)構(gòu)體類型相似,在一個(gè)聯(lián)合體內(nèi)可以定義多種不同的數(shù)據(jù)類型;不同的是,在一個(gè)聯(lián)合體類型的變量中,其所有成員共用同一塊內(nèi)存單元,因此,雖然每一個(gè)成員均可以被賦
37、值,但只有最后一次賦進(jìn)去的成員值能夠保存下來,而先前賦進(jìn)去的那些成員值均被后來的覆蓋了。定義一個(gè)聯(lián)合體類型的一般形式為:union 聯(lián)合體名 成員1類型1;成員2 類型2;.成員n 類型n;例如:union data int a; float b; charc;union data x,y;也可以將類型定義與變量定義合在一起:union dataint a;float b;char c; x,y;聯(lián)合體與結(jié)構(gòu)體雖形式相似,但含義有別。一個(gè)結(jié)構(gòu)體變量所占內(nèi)存長度是各成員占的內(nèi)存長度之和,每個(gè)成員分別占有自己的內(nèi)存單元;而一個(gè)聯(lián)合體變量所占內(nèi)存長度等于其所有成員中最長的成員的長度,所有成員共用一段
38、內(nèi)存單元,所以,有的地方也把聯(lián)合體稱為共用體。11.5.2聯(lián)合體變量的引用對(duì)聯(lián)合體變量的賦值、使用都只能是對(duì)變量的成員進(jìn)行。聯(lián)合體變量的成員表示為:聯(lián)合變量名.成員名例如,對(duì)于上文定義的變量x與y,可使用以下三種方式之一訪問成員值。x.a或者x.b或者y.c在使用聯(lián)合體類型數(shù)據(jù)時(shí)應(yīng)注意以下一些特點(diǎn): 同一內(nèi)存段可以用來存放幾種不同類型的成員,但在每一瞬時(shí)只能存放其中一種,而不是同時(shí)存放幾種。也就是說,每一瞬時(shí)只有一個(gè)成員起作用,其它的成員不起作用,即不是同時(shí)都存在或起作用。 聯(lián)合體變量中起作用的成員是最后一次存放的成員,在存入一個(gè)新的成員后原有的成員就失去作用。例如,以下幾條賦值語句:x.a=
39、1;x.b=3.6;x.c=H;雖然先后給三個(gè)成員賦了值,但只有x.c是有效的,而x.a與x.b已經(jīng)無意義而且也不能被引用了。 聯(lián)合體變量的地址和它的各成員的地址都是同一地址。 不能對(duì)聯(lián)合體變量名賦值,也不能企圖引用變量名來得到成員的值,又不能在定義聯(lián)合體變量時(shí)對(duì)它初始化。例如,下列語句都是錯(cuò)誤的:union data int a;float b;char c; x=1,3.6,H,y; /*錯(cuò),不能初始化 */x=1;/*錯(cuò),不能對(duì)聯(lián)合體變量名賦值*/y=x; /*錯(cuò),不能引用聯(lián)合體變量名以得到值*/ 不能把聯(lián)合體變量作為函數(shù)參數(shù),也不能把一個(gè)函數(shù)的類型定義成聯(lián)合體類型,但可以使用指向聯(lián)合體
40、變量的指針。 聯(lián)合體與結(jié)構(gòu)體可以互相嵌套。在聯(lián)合體中可以定義結(jié)構(gòu)體成員,或者也可以在結(jié)構(gòu)體中定義聯(lián)合體成員。【例11-10】一個(gè)學(xué)校的人員數(shù)據(jù)管理中,教師的數(shù)據(jù)包括:編號(hào)、姓名、性別、職務(wù),學(xué)生的數(shù)據(jù)包括:編號(hào)、姓名、性別、班號(hào)。它們放在同一種表格中,顯然有這么一欄,或者登記教師的“職務(wù)”,或者登記學(xué)生的“班號(hào)”,而不會(huì)在這同一欄中同時(shí)寫上這兩項(xiàng)數(shù)據(jù)。試給出類型定義及輸入輸出方法。編號(hào)num姓名name性別sex職業(yè)job班號(hào)class職務(wù)positionstruct person long num; char name20; char sex; char job;union int clas
41、s; char position20;category;person10;結(jié)構(gòu)體成員job用作身份標(biāo)志,如果輸入為s(學(xué)生),則要對(duì)聯(lián)合體成員category中的class操作,如果輸入為t,則要對(duì)其中的position操作。輸入輸出方法為:scanf( %c,&person0.job);if (person0.job=s) scanf(%d,&person0.category.class);else scanf(%s,&person0.category.position);if (person0.job=s) printf(%d,person0.category.class);else pr
42、intf(%s,person0.category.positon);11.6 枚 舉 類 型所謂“枚舉”類型,是指這種類型變量的取值只能限于事前已經(jīng)一一列舉出來的值的范圍。比如描述星期幾的數(shù)據(jù)就只能在星期日、星期一到星期六之間選擇。用關(guān)鍵字enum定義枚舉類型,如:enum weekday sun, mon, tue, wed, thu, fri, sat;weekday是枚舉類型名,可以用于定義變量,如:enum weekday week1, week2;定義了兩個(gè)枚舉變量,它們只能取sun到sat這七個(gè)值之一,如:week1 = wedweek2 = fri;上述枚舉類型的定義中,sun、
43、mon、.、sat稱為“枚舉元素”或“枚舉常量”。關(guān)于枚舉類型的使用,需要了解以下幾點(diǎn)說明: enum是關(guān)鍵字,標(biāo)識(shí)枚舉類型,定義枚舉類型時(shí)必須用enum開頭。 在定義枚舉類型時(shí),花括號(hào)中的枚舉元素是常量,這些元素的名字是程序設(shè)計(jì)者自己指定的,命名規(guī)則與標(biāo)識(shí)符相同。這些名字只是作為一個(gè)符號(hào),以利于提高程序的可讀性,并無其它固定的含義。 枚舉元素是常量,在編譯器中,按定義時(shí)的排列順序取值0、1、2、.。如:week1 = wed;printf(%d, week1); 輸出整數(shù)3。 枚舉元素是常量,不是變量,可以將枚舉常量賦給一個(gè)枚舉變量,但不能對(duì)枚舉元素賦值。如:week2=sat;/*正確,把
44、枚舉常量sat賦給枚舉變量week2*/sun = 0; mon = 1;/*錯(cuò),不能對(duì)枚舉常量賦值 */但在定義枚舉類型時(shí),可以指定枚舉常量的值,如:enum weekday sun=7, mon=1, tue, wed, thu, fri, sat;此時(shí),tue、wed、.的值從mon的值順序加1。如,tue=2。 枚舉值可以作判斷比較,如:if (week1 = mon).if (week1 sun).枚舉值的比較規(guī)則是以其在定義時(shí)的順序號(hào)大小為依據(jù)。如果定義時(shí)未人為指定,則第一個(gè)枚舉元素的值認(rèn)作0。故有sunmon,montue等關(guān)系。 整型與枚舉類型是不同的數(shù)據(jù)類型,不能直接賦值。例
45、如:work1 = 2; /*錯(cuò),work1是枚舉類型,只能在指定范圍內(nèi)獲取枚舉元素 */但可以通過強(qiáng)制類型轉(zhuǎn)換賦值。例如:work1 = (enum weekday)2; /*即取tue */ 枚舉常量不是字符串,不能用下面的方法輸出字符串“sun”:printf(%s,sun) ;而應(yīng)用檢查的方法去處理:if (week1=sun) printf(sun);【例11-11】main() enum color_name red,yellow,blue,white,black; enum color_name color; for (color=red;color=black;color+)
46、switch (color) case red: printf(red,%dn,red);break; case yellow: printf(yellow,%dn,yellow);break; case blue: printf(blow,%dn,blue);break; case white: printf(white,%dn,white);break; default: printf(black,%dn,black);break; 運(yùn)行結(jié)果如下:red,0yellow,1blue,2white,3black,411.7 用typedef定義類型1概念在C語言中允許用關(guān)鍵字typedef定
47、義一種新的類型名來代替已有的類型名。例如:typedef int INTEGER;typedef float REAL;定義了新的數(shù)據(jù)類型INTEGER和REAL,它們代表已有數(shù)據(jù)類型int和float。通過上述定義后,以下兩行等價(jià):int i, j ; float a, b;INTEGER i, j;REAL a, b;2典型用法定義一種新數(shù)據(jù)類型,作簡單的名字替換。例如:typedef unsigned int uint; /*定義uint無符號(hào)整型。*/uint u1; /* 用uint定義變量u1為無符號(hào)整型 */簡化數(shù)據(jù)類型的書寫。例如:typedef struct int mont
48、h;int day;int year;DATE ;DATE birthday;DATE *p;DATE d7;定義數(shù)組類型。例如:typedef int NUM100;/* 數(shù)據(jù)類型NUM為整型數(shù)組類型 */NUM n; /*用NUM定義一個(gè)整型數(shù)組n,含有100個(gè)元素 */定義指針類型。例如:typedef char * STRING; /* STRING是字符指針類型 */STRING p, s10; /* p是字符指針變量,s10是字符指針數(shù)組 */3說明typedef只是起了一個(gè)新的類型名字,并未建立新的數(shù)據(jù)類型,它是已有類型(int)的別名,好處是往往增加程序的可讀性,便于快速理解某
49、些變量的含義。在編譯時(shí),與原類型等價(jià)。而#define定義一個(gè)宏, 在預(yù)編譯時(shí)就做相應(yīng)的替換。宏替換的對(duì)象可以是某種數(shù)據(jù)類型,也可以是其它程序體,替換對(duì)象不受限制。11.8 位 運(yùn) 算 符在計(jì)算機(jī)內(nèi)部,程序的運(yùn)行、數(shù)據(jù)的存儲(chǔ)及運(yùn)算都是以二進(jìn)制的形式進(jìn)行的。一個(gè)字節(jié)由八個(gè)二進(jìn)制位組成。本節(jié)講的位運(yùn)算,是指進(jìn)行二進(jìn)制位的運(yùn)算。位運(yùn)算是C語言有別于其他高級(jí)語言的一種強(qiáng)大的運(yùn)算,它使得C語言具有了某些低級(jí)語言的功能,使程序可以進(jìn)行二進(jìn)制的運(yùn)算。表11-1列出了位操作的運(yùn)算符,位運(yùn)算符的操作對(duì)象為整型或字符型數(shù)據(jù)。下面一一列舉說明。表11-1位運(yùn)算符含 義舉 例按位取反a,對(duì)變量a中全部二進(jìn)制位取反左移
50、a 右移a 2,a中各位全部右移2位,左邊補(bǔ)0&按位與a & b,a和b中各位按位進(jìn)行“與”運(yùn)算|按位或a | b,a和b中各位按位進(jìn)行“或”運(yùn)算按位異或a b,a和b中各位按位進(jìn)行“異或”運(yùn)算按位取反運(yùn)算符按位取反運(yùn)算符“”是一個(gè)單目運(yùn)算符,能對(duì)一個(gè)二進(jìn)制數(shù)的每一位都取反,即0變?yōu)?,1變?yōu)?。例如:a= 0 0 0 1 1 0 1 0(十六進(jìn)制為1a)a= 1 1 1 0 0 1 0 1(十六進(jìn)制為e5)【例11-12】main() unsigned char a,b; a=26; printf(%d,%xn,a,a); b=a; printf(%d,%xn,b,b);運(yùn)行結(jié)果為:26,1
51、a229,e5左移運(yùn)算符左移運(yùn)算符“”的功能是將一個(gè)數(shù)的各個(gè)二進(jìn)制位全部向左平移若干位,左邊移出的部分予以忽略,右邊空出的位置補(bǔ)零。如:a= 0 0 0 1 1 0 1 0(十六進(jìn)制為1a)a”的功能是將一個(gè)數(shù)的各個(gè)二進(jìn)制位全部向右平移若干位,右邊移出的部分予以忽略,左邊空出的位置對(duì)于無符號(hào)數(shù)補(bǔ)零,對(duì)于有符號(hào)數(shù),若原符號(hào)位為0,則補(bǔ)0,若原符號(hào)位為1,則全補(bǔ)1。也就是右移后保持這個(gè)數(shù)的正負(fù)符號(hào)不變。例如,若變量a被定義成unsigned char,即無符號(hào)型,則有:a= 1 0 0 1 1 0 1 0(十六進(jìn)制為9a)a2= 0 0 1 0 0 1 1 0(十六進(jìn)制為26)若變量a被定義成 c
52、har,即有符號(hào)型,則有:a= 1 0 0 1 1 0 1 0(十六進(jìn)制為9a)a2= 1 1 1 0 0 1 1 0(十六進(jìn)制為e6)同樣,一個(gè)數(shù)據(jù)每右移1位相當(dāng)于除以2,右移2位相當(dāng)于除以4,以此類推。按位與運(yùn)算符運(yùn)算符“&”將其兩邊數(shù)據(jù)對(duì)應(yīng)的各個(gè)二進(jìn)制位分別進(jìn)行“與”運(yùn)算,即二者都為1時(shí)結(jié)果為1,否則為0。如:a= 1 0 1 1 1 0 1 0(十六進(jìn)制為ba)b= 0 1 1 0 1 1 1 0(十六進(jìn)制為6e)a&b= 0 0 1 0 1 0 1 0(十六進(jìn)制為2a)可以發(fā)現(xiàn),任何一位與1“與”運(yùn)算時(shí),結(jié)果保持原值,與0“與”運(yùn)算時(shí),結(jié)果皆為0?!纠?1-13】將一個(gè)十進(jìn)制數(shù)轉(zhuǎn)換為
53、二進(jìn)制數(shù)。C語言中printf函數(shù)提供的%x、%d、%o格式符可將一個(gè)整數(shù)以十六進(jìn)制、十進(jìn)制或八進(jìn)制的形式輸出,但沒有二進(jìn)制輸出格式。人工轉(zhuǎn)換的方法是設(shè)置一個(gè)屏蔽字,其中只有一位是1,其余各位均為0,與被轉(zhuǎn)換數(shù)進(jìn)行與運(yùn)算,根據(jù)運(yùn)算結(jié)果判斷被測試的那一位是1還是0,其余二進(jìn)位的測試方法相同。一個(gè)整數(shù)占兩個(gè)字節(jié),共有十六個(gè)二進(jìn)制位。main() int i,bit; unsigned int n,mask; mask=0 x8000; /*最高位為1,其余位為0*/ printf(enter your number:); scanf(%d,&n); printf(binary of %d is:,
54、n); for(i=0;i1; /*右移一位,得到下一個(gè)屏蔽字*/ 按位或運(yùn)算符運(yùn)算符“|”將兩邊對(duì)應(yīng)的二進(jìn)制位分別進(jìn)行“或”運(yùn)算,即二者之中只要有一個(gè)為1時(shí)結(jié)果就為1,兩者都為0時(shí)結(jié)果才為0。如:a= 1 0 0 1 1 0 1 0(十六進(jìn)制為9a)b= 0 1 0 1 0 1 1 0(十六進(jìn)制為56)a|b= 1 1 0 1 1 1 1 0(十六進(jìn)制為de)可以發(fā)現(xiàn),任何一位與0“或”時(shí),其結(jié)果就等同于這一位?!纠?1-14】循環(huán)移位。一般移位時(shí),無論是左移,還是右移,從一端移出的數(shù)據(jù)位總會(huì)丟失。而循環(huán)移位的目標(biāo)是將移出來的幾位,從另一端移進(jìn)來,從而不丟失任何數(shù)據(jù)位。對(duì)無符號(hào)整數(shù)a循環(huán)右移n位的步驟是:使a中各位左移(16-n)位,使右端的n位放到b中的高n位中,其余各位補(bǔ)0,可用下面的語句實(shí)現(xiàn):b=an;使b與c按位“或”運(yùn)算,得到最終結(jié)果。程序如下:main() unsigned int a,b,c;
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 水庫堤壩安全護(hù)欄建設(shè)協(xié)議
- 建筑起重機(jī)械租賃協(xié)議
- 藝術(shù)表演辦公室租賃合同
- 寫字樓木地板安裝協(xié)議
- 銀行服務(wù)工作心得和體會(huì)
- 整形外科專家合作協(xié)議
- 婚禮音響設(shè)備租賃合同范本
- 節(jié)能環(huán)保設(shè)備生產(chǎn)三方合作協(xié)議
- 環(huán)保工程挖掘租賃合同
- 2024年展會(huì)組織與管理合作協(xié)議
- 2024年教師普通話培訓(xùn)心得體會(huì)范文3篇
- 車寨礦井及選煤廠1.5Mt-a新建工程環(huán)評(píng)
- 2024年T8聯(lián)考高三第二次學(xué)業(yè)質(zhì)量語文試題答案講評(píng)課件
- 【川教版】一年級(jí)上冊(cè) 《生命 生態(tài) 安全》第一課 我和我的布娃娃 課件
- 設(shè)備管理的標(biāo)準(zhǔn)化與規(guī)范化
- 公司組織架構(gòu)圖
- 藥品非處方藥市場調(diào)研報(bào)告
- 人教版八年級(jí)英語下冊(cè)各單元知識(shí)點(diǎn)匯總
- 體育科學(xué)研究方法-第四章第四節(jié)實(shí)驗(yàn)法
- 一起電動(dòng)自行車火災(zāi)事故原因認(rèn)定和分析
- 廣東省廣州市2023-2024學(xué)年高一上學(xué)期1月期末英語英語試題(解析版)
評(píng)論
0/150
提交評(píng)論