結(jié)構(gòu)體、共用體與枚舉類型課件_第1頁
結(jié)構(gòu)體、共用體與枚舉類型課件_第2頁
結(jié)構(gòu)體、共用體與枚舉類型課件_第3頁
結(jié)構(gòu)體、共用體與枚舉類型課件_第4頁
結(jié)構(gòu)體、共用體與枚舉類型課件_第5頁
已閱讀5頁,還剩71頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

結(jié)構(gòu)體、共用體與枚舉類型

8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量8.1.1結(jié)構(gòu)體概述

例8-1

通過建立表8-1的學(xué)生的信息表,要求從鍵盤輸入學(xué)生的信息,并將學(xué)生成績小于平均成績的學(xué)生信息輸出。

學(xué)號姓名性別年齡成績1001ZhangM19881002LiM18901003WangF20891004ZhaoM19838.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量#include<stdio.h>#defineN4voidmain(){intnum[N]; /*存放各學(xué)生的學(xué)號

*/

charname[N][10]; /*存放各學(xué)生的姓名

*/

charsex[N]; /*存放各學(xué)生的性別*/

intage[N]; /*存放各學(xué)生的年齡*/

floatscore[N]; /*存放各學(xué)生的成績*/

inti;floatsum=0,aver; /*表示總成績和平均成績

*/

for(i=0;i<N;i++){scanf("%d%s%c%d%f",&num[i],name[i],&sex[i],&age[i],&score[i]);sum+=score[i];}aver=sum/N;printf("\n");8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量for(i=0;i<N;i++)if(score[i]<aver)printf("%d%s%c%d%f\n",num[i],name[i],sex[i],age[i],score[i]);}由于程序num、name、sex、age、score分別定義為互相獨立的數(shù)組,難以反映它們之間的內(nèi)在聯(lián)系。

8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量#include<stdio.h>#defineN4structstudent /*定義學(xué)生類型結(jié)構(gòu)體

*/{intnum; /*學(xué)號成員

*/

charname[20]; /*姓名成員

*/

charsex; /*性別成員

*/

intage; /*年齡成員

*/

floatscore; /*成績成員

*/};voidmain(){structstudentstu[N]; /*定義學(xué)生結(jié)構(gòu)體類型數(shù)組

*/inti;floatsum=0,aver; /*表示總成績和平均成績

*/8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量for(i=0;i<N;i++){scanf("%d%s%c%d%f",&stu[i].num,stu[i].name,&stu[i].sex,&stu[i].age,&stu[i].score);sum+=stu[i].score;}aver=sum/N;printf("\n");for(i=0;i<N;i++)if(stu[i].score<aver)printf("%d%s%c%d%f\n",stu[i].num,stu[i].name,stu[i].sex,stu[i].age,stu[i].score);}8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量說明:使用結(jié)構(gòu)體數(shù)據(jù),可將一個學(xué)生的數(shù)據(jù)有機(jī)組合起來,例中的stu是個結(jié)構(gòu)體數(shù)組,stu[i]表第i個學(xué)生的數(shù)組,stu[i].num表第i個學(xué)生的學(xué)號,stu[i].name表第i個學(xué)生的姓名等。結(jié)構(gòu)體的每一個成員都是通過其名字來引用,引用形式如下:結(jié)構(gòu)體變量名.成員名結(jié)構(gòu)體的引入為處理復(fù)雜的數(shù)據(jù)結(jié)構(gòu)提供了有力的手段(如鏈表等),也為函數(shù)間傳遞一組不同類型的數(shù)據(jù)提供了方便。特別是對于數(shù)據(jù)結(jié)構(gòu)比較復(fù)雜的大型程序提供了方便。8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量8.1.2結(jié)構(gòu)體的聲明

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

{

結(jié)構(gòu)成員1;

結(jié)構(gòu)成員2;……

結(jié)構(gòu)成員n;}其中,struct為結(jié)構(gòu)體定義的關(guān)鍵字,不能省略。結(jié)構(gòu)體名由用戶給定,即是定義的結(jié)構(gòu)體類型名。用兩個花括號括住的內(nèi)容是該結(jié)構(gòu)體中的各個成員,每個成員又有自己的數(shù)據(jù)類型,它們可以是整型、實型、字符型、指針或結(jié)構(gòu)類型等,它們都應(yīng)進(jìn)行類型說明。

8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量有關(guān)結(jié)構(gòu)體的幾點說明:結(jié)構(gòu)體類型的定義只是說明了一種結(jié)構(gòu)體的組織形式,在編譯時并不為它分配存儲空間。只是在定義結(jié)構(gòu)體類型變量后,才為變量按照其組織形式分配內(nèi)存空間。結(jié)構(gòu)體的成員可以是簡單變量、數(shù)組、指針,還可以是另一個已定義的結(jié)構(gòu)體或共用體變量。當(dāng)定義一個結(jié)構(gòu)體的成員又是一個結(jié)構(gòu)體類型,這稱為結(jié)構(gòu)體的嵌套定義。structdate{intyear;intmonth;intday;};structstudent{intnum;charname[20];charsex;structdatebirthday;floatscore;};8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量結(jié)構(gòu)體定義可以在函數(shù)內(nèi)部,也可在函數(shù)外部。在函數(shù)內(nèi)部定義的結(jié)構(gòu)體,只有在函數(shù)內(nèi)部使用,在函數(shù)外部定義的結(jié)構(gòu)體,從定義點起到源文件尾之間的所有函數(shù)都可使用。結(jié)構(gòu)體成員的名字可以同程序中的其他變量名相同,兩者的意義不同,不會相混。

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

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

structstudent{intnum;charname[20];charsex;intage;floatscore;};structstudentstu1,stu2;8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量在聲明類型的同時定義變量

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

成員列表;}變量名表列;structstudent{intnum;charname[20];charsex;intage;floatscore;}stu1,stu2;8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量直接定義結(jié)構(gòu)類型變量

struct{

成員表列;}變量名表列;struct{intnum;charname[20];charsex;intage;floatscore;}stu1,stu2;8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量對結(jié)構(gòu)體變量,系統(tǒng)要為其分配存儲空間。一個結(jié)構(gòu)體變量所占存儲空間的大小,是其所含結(jié)構(gòu)體成員所占存儲空間的總和,這些結(jié)構(gòu)體成員所占的存儲空間是由一組連續(xù)的存儲空間所組成。

也可用sizeof運算來求得,一個變量或數(shù)據(jù)類型在內(nèi)存中所占內(nèi)存空間的字節(jié)數(shù),使用形式是:sizeof(變量名)或

sizeof(類型標(biāo)識符)8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量8.1.4結(jié)構(gòu)體變量的引用C語言中除兩個相同類型結(jié)構(gòu)體變量可以相互整體賦值外,不能對結(jié)構(gòu)體變量名直接引用,只能對結(jié)構(gòu)體變量中的成員分別進(jìn)行引用,即對結(jié)構(gòu)變量的操作,如賦值、輸入、輸出、運算等都是通過結(jié)構(gòu)變量的成員來實現(xiàn)的。結(jié)構(gòu)體變量的引用格式

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

stu1.num=10001;strcpy(,"zhang");/*此處不能寫成

="zhang"*/stu1.sex='M';stu1.age=19;stu1.score=88;不能把結(jié)構(gòu)變量作為整體進(jìn)行輸入輸出,下面的引用方式是錯誤的:scanf("%d%s%c%d%f",stu1);正確的引用方式可以是:gets();scanf("%d%c%d%f",&stu1.num,&stu1.sex,&stu1.age,&stu1.score);

8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量結(jié)構(gòu)體嵌套時逐級引用

structdate{intmonth;intday;intyear;};structperson{charname[20];charsex;structdatebirthday;};structpersonperson1;person1.birthday.month8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量同類型結(jié)構(gòu)體變量間的整體賦值

結(jié)構(gòu)體變量可以通過整體賦值,將一個結(jié)構(gòu)體變量中的所有數(shù)據(jù),賦給另一個結(jié)構(gòu)體類型相同的結(jié)構(gòu)體變量中對應(yīng)的數(shù)據(jù)成員。

例8-2

建立一個學(xué)生的基本情況表,然后將其打印輸出。

#include<stdio.h>#include<string.h>main(){structstudent{intnum;charname[20];charsex;intage;floatscore;}stu1,stu2;8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量stu1.num=10001;strcpy(,"zhang");stu1.sex='M';stu1.age=19;stu1.score=88;stu2=stu1; /*同類結(jié)構(gòu)體變量之間可以賦值*/

printf("stu1:%d,%s,%c,%d,%6.2f\n",stu1.num,,stu1.sex,stu1.age,stu1.score);printf("stu2:%d,%s,%c,%d,%6.2f\n",stu2.num,,stu2.sex,stu2.age,stu2.score);}8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量8.1.5結(jié)構(gòu)體變量的初始化

結(jié)構(gòu)體變量定義時的初始化形式如下:struct結(jié)構(gòu)體名

變量名={各成員值列表};#include<stdio.h>#include<string.h>main(){structstudent{intnum;charname[20];charsex;intage;floatscore;}stu2,stu1={10001,"zhang",'M',19,88};stu2=stu1;printf("stu1:%d,%s,%c,%d,%6.2f\n",stu1.num,,stu1.sex,stu1.age,stu1.score);printf("stu2:%d,%s,%c,%d,%6.2f\n",stu2.num,,stu2.sex,stu2.age,stu2.score);}8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量8.1.6指向結(jié)構(gòu)體的指針

可以用一個指針指向結(jié)構(gòu)體變量,指向結(jié)構(gòu)體變量的指針的值是該結(jié)構(gòu)體變量所分配的存儲區(qū)域的首地址。

結(jié)構(gòu)指針變量的定義

structstudent{intnum;charname[20];charsex;intage;floatscore;

}stu1={10001,"zhang",'M',19,88};structstudent*p=&stu1;8.1結(jié)構(gòu)體類型與結(jié)構(gòu)體變量通過指針訪問結(jié)構(gòu)體變量的成員(結(jié)構(gòu)體類型數(shù)據(jù)的間接引用)

結(jié)構(gòu)變量中簡單成員的引用形式有下面3種:結(jié)構(gòu)變量名.成員名(名字引用)結(jié)構(gòu)指針->成員名(指針引用)(*結(jié)構(gòu)指針).成員名

例8-3

使用指向結(jié)構(gòu)變量的指針來訪問輸出結(jié)構(gòu)變量的各個成員的值。#include<stdio.h>#include<string.h>voidmain(){structstudent{intnum;charname[20];charsex;intage;floatscore;}stu1={10001,"zhang",'M',19,88};structstudent*p=&stu1;/*定義指向結(jié)構(gòu)體變量stu1的指針p*/printf("%d,%s,%c,%d,%6.2f\n",p->num,p->name,p->sex,p->age,p->score);}8.2結(jié)構(gòu)體數(shù)組

8.2.1結(jié)構(gòu)體數(shù)組的定義

structstudent{intnum;charname[20];charsex;intage;floatscore;};structstudentstu[10];8.2結(jié)構(gòu)體數(shù)組

8.2.2結(jié)構(gòu)體數(shù)組的初始化

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

結(jié)構(gòu)體數(shù)組名[]={{第0個元素各成員}{第1個元素各成員},……};例如:structstudent{intnum;charname[20];charsex;intage;floatscore;}stu[4]={{10001,"Zhang",'M',19,88},{10002,"Li",'M',18,90},{10003,"He",'F',20,92},{10004,"Cheng",'F',18,70}};8.2結(jié)構(gòu)體數(shù)組

8.2.3結(jié)構(gòu)體數(shù)組與指針

可以用一個指針指向結(jié)構(gòu)體數(shù)組,指向結(jié)構(gòu)體數(shù)組的指針的值是該結(jié)構(gòu)體數(shù)組所分配的存儲區(qū)域的首地址。

structstudent{intnum;charname[20];charsex;intage;floatscore;};structstudent*p;structstudentstu[10];p=stu;8.2結(jié)構(gòu)體數(shù)組

p->num; /*引用stu[0].num*/p++; /*p+1后指向stu[1]起始地址*/p->num; /*引用stu[1].num*/8.2.4結(jié)構(gòu)體數(shù)組的應(yīng)用實例

例8-4

建立10名學(xué)生的信息表,每個學(xué)生的數(shù)據(jù)包括學(xué)號、姓名、及三門課的成績。要求從鍵盤輸入這10名學(xué)生的信息,并按照每一行顯示一名學(xué)生信息的形式將10名學(xué)生的信息顯示出來。

#defineN10 /*N代表學(xué)生人數(shù)*/#include<stdio.h>#include<string.h>structstudent /*定義student結(jié)構(gòu)體類型*/{intnum;charname[20];floatscore[3];};8.2.4結(jié)構(gòu)體數(shù)組的應(yīng)用實例

voidmain(){inti,j;structstudentstu[N];for(i=0;i<N;i++) /*用for循環(huán)輸入10名學(xué)生的信息*/{scanf("%d,%s",&stu[i].num,stu[i].name);for(j=0;j<3;j++) /*輸入每個學(xué)生三門課的成績*/

scanf("%f",&stu[i].score[j]);}for(i=0;i<N;i++){printf("%d",stu[i].num);printf("%s",stu[i].name);

printf("%6.1f,%6.1f,%6.1f\n",stu[i].score[0],

stu[i].score[1],stu[i].score[2]);}}8.2.4結(jié)構(gòu)體數(shù)組的應(yīng)用實例

例8-5

用指向結(jié)構(gòu)體數(shù)組的指針改寫例8-4voidmain(){inti,j;structstudent*p,stu[N];p=stu;for(i=0;i<N;i++){scanf("%d,%s",&stu[i].num,stu[i].name);for(j=0;j<3;j++)scanf("%f",&stu[i].score[j]);}for(p=stu;p<stu+N;p++) /*p是指向結(jié)構(gòu)體數(shù)組的指針*/{printf("%d",p->num);printf("%s",p->name);printf("%6.1f,%6.1f,%6.1f\n",p->score[0],p->score[1],p->score[2]);}}8.3結(jié)構(gòu)體與函數(shù)

8.3.1結(jié)構(gòu)體變量作函數(shù)參數(shù)

例8-6

在例8-4中,10名學(xué)生的信息輸出改為通過調(diào)用print函數(shù)完成。

voidmain(){inti,j;structstudentstu[N];voidprint(structstudentstu);for(i=0;i<N;i++){scanf("%d%s",&stu[i].num,stu[i].name);for(j=0;j<3;j++)scanf("%f",&stu[i].score[j]);}for(i=0;i<N;i++)print(stu[i]);}voidprint(structstudentstu){printf("%d,%s,%6.1f,%6.1f,%6.1f\n",stu.num,stu.name,stu.score[0],stu.score[1],stu.score[2]);}8.3結(jié)構(gòu)體與函數(shù)

8.3.2結(jié)構(gòu)體數(shù)組作函數(shù)參數(shù)

例8-7

將例8-5中的結(jié)構(gòu)體數(shù)組的輸入與輸出都寫成函數(shù),在main函數(shù)中調(diào)用這些函數(shù)實現(xiàn)10名學(xué)生的信息輸入及輸出。

voidmain(){inti,j;structstudentstu[N];voidmyscan(structstudentstu[],intn); /*函數(shù)聲明*/

voidmyprint(structstudentstu[],intn); /*函數(shù)聲明*/

myscan(stu,N);myprint(stu,N);getch();}8.3結(jié)構(gòu)體與函數(shù)

voidmyscan(structstudentstu[],intn) /*輸入n個學(xué)生記錄函數(shù)*/{inti,j;for(i=0;i<n;i++){scanf("%d%s",&stu[i].num,stu[i].name);for(j=0;j<3;j++)scanf("%f",&stu[i].score[j]);}}8.3結(jié)構(gòu)體與函數(shù)

voidmyprint(structstudentstu[],intn) /*輸出n個學(xué)生記錄函數(shù)*/{inti,j;for(i=0;i<n;i++){printf("%d%s",stu[i].num,stu[i].name);for(j=0;j<3;j++)printf("%6.1f",stu[i].score[j]);printf("\n");}}8.3結(jié)構(gòu)體與函數(shù)8.3.3返回結(jié)構(gòu)體指針的函數(shù)例8-8

建立10名學(xué)生的信息表,每個學(xué)生的數(shù)據(jù)包括學(xué)號、姓名、及三門課的成績。輸出總分最高的學(xué)生記錄,要求將查找該記錄的過程編制為函數(shù)。

#include<stdio.h>#include<string.h>#defineN10structstudent{intnum;charname[20];floatscore[3];floatsum;};

8.3結(jié)構(gòu)體與函數(shù)main(){structstudent*search_max(structstudent*x,intn);inti,j;structstudentstu[N],*p;for(i=0;i<N;i++){scanf("%d%s",&stu[i].num,stu[i].name);stu[i].sum=0;for(j=0;j<3;j++){scanf("%f",&stu[i].score[j]);stu[i].sum=stu[i].sum+stu[i].score[j];}}p=search_max(stu,N); /*調(diào)用查找最高分記錄函數(shù)

*/

printf("%d,%s",p->num,p->name);printf("%6.1f,%6.1f,%6.1f,%6.1f\n",p->score[0],p->score[1],p->score[2],p->sum);}8.3結(jié)構(gòu)體與函數(shù)/*查找最高分學(xué)生的記錄函數(shù),返回值為指向該記錄的指針

*/

structstudent*search_max(structstudent*x,intn){inti,k=0;for(i=1;i<n;i++)if((x+i)->sum->(x+k)>sum)k=i; /*與if(x[i].sum>x[k].sum)k=i;等價

*/

returnx+k; /*返回最高分記錄的指針

*/}8.4共用體

共用體是另一種構(gòu)造型數(shù)據(jù)類型,是多種變量共享一片內(nèi)存空間。直觀地講,共用體可以把所在存儲單元中相同的數(shù)據(jù)部分當(dāng)作不同的數(shù)據(jù)類型來處理,或用不同的變量名來引用相同的數(shù)據(jù)部分。共用體常用于需要頻繁進(jìn)行類型轉(zhuǎn)換的場合,及壓縮數(shù)據(jù)字節(jié)或程序移植等方面。

8.4.1共用體和共用體變量

共用體的定義

union共用體類型名{

共用體成員表列;}共用體變量名表列;8.4共用體定義共用體類型的同時定義共用體變量。例如:uniondata{intnum;charch;}unvt;直接定義無共用體類型名的共用體變量。例如:union{intnum;charch;}unvt;8.4共用體先定義一個共用體類型名,再用定義的共用體類型定義共用體變量。例如:uniondata{intnum;charch;};uniondataunvt;共用體在內(nèi)存的存放形式

共用體的成員變量存儲時共用同一起始地址的存儲單元,所占內(nèi)存為最大內(nèi)存需求的成員所占內(nèi)存

8.4共用體對共用體變量使用時需要注意的幾個問題

系統(tǒng)采用覆蓋技術(shù),實現(xiàn)共用變量各成員的內(nèi)存共享,所以在某一時刻,存放的和起作用的是最后一次存入的成員值。

由于所有成員共享同一內(nèi)存空間,故共用變量與其他成員的地址相同。

不能對共用變量進(jìn)行初始化(注意:結(jié)構(gòu)變量可以);也不能將共用變量作為函數(shù)參數(shù),以及使函數(shù)返回一個共用體數(shù)據(jù),但可以使用指向共用變量的指針。

共用體類型可以出現(xiàn)在結(jié)構(gòu)類型定義中,反之亦然。

8.4共用體8.4.2共用體變量的引用方式

uniondataunvt,*pu; /*聲明了共用體變量unvt和指向共用體的指針變量pu*/pu=&unvt;

/*使共用體指針變量pu指向共用體變量unvt*/unvt.num和pu->num /*對成員num用共用體變量直接引用和指針的間接引用*/unvt.ch和pu->ch /*對成員ch用共用體變量直接引用和指針的間接引用*/8.4共用體8.4.3共用體應(yīng)用舉例

例8-10

假設(shè)一個學(xué)生的信息表中包括學(xué)號、姓名和一門課的成績。而成績通常又可采用兩種表示方法:一種是五分制,采用的是整數(shù)形式;另一種是百分制,采用的是浮點數(shù)形式,現(xiàn)要求編一程序,輸入一個學(xué)生的信息并顯示出來。#include<stdio.h>structstu_score{intnum;charname[20];inttype; /*type值為0時五分制,type值為1時百分制*/

unionmixed{intiscore; /*五分制*/

floatfscore; /*百分制*/}score;};8.4共用體voidmain(){structstu_scorestud1;printf("pleaseinputnum,name,type:\n");scanf("%d%s%d",&stud1.num,,&stud1.type);if(stud1.type==0) /*采用五分制*/{printf("pleaseinputiscore");scanf("%d",&stud1.score.iscore);}elseif(stud1.type==1) /*采用百分制*/{printf("pleaseinputfscore");scanf("%f",&stud1.score.fscore);}if(stud1.type==0)printf("%d,%s,%d,%d",stud1.num,,stud1.type,stud1.score.iscore);elseif(stud1.type==1)printf("%d,%s,%d,%f",stud1.num,,stud1.type,stud1.score.fscore);}8.5枚舉類型

枚舉類型就是將變量可能出現(xiàn)的值放在一起而形成的一個整型常量的集合類型,限制在此集合內(nèi),變量只能取這個集合中的某個值。

枚舉類型的定義enum枚舉類型名

{取值表};enumweekdays{Sun,Mon,Tue,Wed,Thu,Fri,Sat};枚舉變量的定義

間接定義:先聲明類型,再定義變量

enumweekdaysworkday;直接定義:聲明類型類型的同時直接定義變量

enumweekdays{Sun,Mon,Tue,Wed,Thu,Fri,Sat}workday;8.5枚舉類型

說明

枚舉型僅適應(yīng)于取值有限的數(shù)據(jù)

取值表中的值稱為枚舉元素,枚舉元素是常量。在C編譯器中,按定義的順序取值0、1、2、...。所以枚舉元素可以進(jìn)行比較,比較規(guī)則是:序號大者為大。

枚舉元素的值也是可以人為改變的:在定義時由程序指定

在使用枚舉量時,通常關(guān)心的不是它的數(shù)值大小,而是它所代表的狀態(tài),在程序中,可以用不同的枚舉量來表示不同的處理方式。正確地使用枚舉變量,有利于提高程序的可讀性。

8.5枚舉類型

例8-11

若十月一號是星期五,任給十月中的一天(1~30),試判斷該天是星期幾,并將其輸出。

#include<stdio.h>main(){enumweekdays{sun,mon,tue,wed,thu,fri,sat}date;inti;printf("pleaseinputthedate(1-30):");scanf("%d",&i);date=(enumweekdays)(i+4)%7;switch(date){casesun:

printf("Sunday\n");break;casemon:printf("Monday\n");break;casetue:printf("Tuesday\n");break;

8.5枚舉類型

casewed:

printf("Wednesday\n");break;casethu:

printf("Thursday\n");break;casefri:

printf("Friday\n");break;casesat:

printf("Saturday\n");break;default:

printf("inputerror!");break;}}8.6自定義類型標(biāo)識符

自定義類型標(biāo)識符(typedef)的使用

除可直接使用C提供的標(biāo)準(zhǔn)類型和自定義的類型(結(jié)構(gòu)、共用、枚舉)外,也可使用typedef定義已有類型的別名(自定義類型標(biāo)識符),來代替已有的int、char、float、結(jié)構(gòu)體等數(shù)據(jù)類型,該別名與標(biāo)準(zhǔn)類型名一樣,可用來定義相應(yīng)的變量。

以實型float定義一個別名REAL為例,說明定義已有類型別名的方法如下:按定義實型變量的方法,寫出定義體:floatf;將變量名換成別名:floatREAL;在定義體最前面加上typedef:

typedeffloatREAL;8.6自定義類型標(biāo)識符

例8-12

定義一個學(xué)生類型的別名,將例8-3的程序改寫如下:#include<stdio.h>#include<string.h>typedefstructstudent{intnum;charname[20];charsex;intage;floatscore;}STUDENT;voidmain(){STUDENTstu1={10001,"zhang",'M',19,88};STUDENT*p=&stu1; /*定義指向結(jié)構(gòu)體變量stu1的指針p*/printf("%d,%s,%c,%d,%6.2f\n",p->num,p->name,p->sex,p->age,p->score);}8.6自定義類型標(biāo)識符

有關(guān)自定義類型標(biāo)識符(typedef)的說明

用typedef只是給已有類型增加一個別名,并不能創(chuàng)造一個新的類型。

typedef與#define有相似之處,但兩者是不同的:前者是由編譯器在編譯時處理的,后者是由編譯預(yù)處理器在編譯預(yù)處理時處理的,而且只能作簡單的字符串替換。

8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表

8.7.1問題的提出

數(shù)組是順序存儲結(jié)構(gòu),在內(nèi)存中占用一段連續(xù)的存儲空間,它的特點是在邏輯上相鄰的兩個元素在物理位置上也相鄰,因此,可以隨機(jī)存取表中任一元素,它的存儲位置可用一個簡單、直觀的公式來表示,數(shù)組的存儲位置和存儲空間的大小在它被聲明時由系統(tǒng)分配的,在程序運行期間不變。而有時我們常常會很難確定元素的個數(shù),譬如一個班級的學(xué)生,因為班級大小不同,學(xué)生數(shù)不一樣,為了能存放任何班級的學(xué)生數(shù),必須把數(shù)組定義的足夠大,但這樣會造成存儲空間的浪費,而且在數(shù)組中插入和刪除一個元素時要引起大量數(shù)據(jù)的移動,且數(shù)據(jù)量的擴(kuò)充將會受到所占用存儲空間的限制。鏈表是動態(tài)地進(jìn)行存儲分配的一種數(shù)據(jù)結(jié)構(gòu),鏈表的各個結(jié)點元素在邏輯上是連續(xù)排列的,但在物理上,即內(nèi)存中存儲時并不占用連續(xù)的存儲空間,能有效地避免存儲空間的浪費和數(shù)據(jù)移動問題。鏈表是由頭指針和一列表結(jié)點通過指針鏈接而成。鏈表預(yù)先不必定義其結(jié)點的最大數(shù)目,在程序執(zhí)行期間,可以根據(jù)需要增加或刪除鏈表中的結(jié)點。8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表

數(shù)組鏈表存放的數(shù)據(jù)量固定可變存儲空間連續(xù)不連續(xù)存取數(shù)據(jù)方便不方便適用場合可事先確定所需處理的數(shù)據(jù)量程序執(zhí)行時需要動態(tài)改變數(shù)據(jù)量8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表8.7.2鏈表的基本結(jié)構(gòu)

頭指針(head),是一個指針變量,用來存放鏈表中第一個結(jié)點的地址。只要由頭指針?biāo)赶虻念^結(jié)點出發(fā),就可以訪問鏈表中任何一個結(jié)點的數(shù)據(jù)成員。鏈表中每一結(jié)點一般由兩大部分組成:數(shù)據(jù)域,用于存放用戶需要用的實際數(shù)據(jù),可以是一個數(shù)據(jù)項,也可以是多個數(shù)據(jù)項。指針域,用于存放和該結(jié)點相鏈接的下一個結(jié)點的地址。指針域是同類型的結(jié)構(gòu)體指針變量。鏈表中最后一個結(jié)點因其后續(xù)無結(jié)點,該指針域不再指向其他結(jié)點,它稱為尾結(jié)點,它的地址部分存放一個“NULL”(表示空地址),鏈表到此結(jié)束。

8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表8.7.3鏈表結(jié)點的定義

鏈表結(jié)點數(shù)據(jù)可以用結(jié)構(gòu)體來描述

structstudent{intnum;floatscore;structstudent*next; /*指針域*/};8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表8.7.4單向鏈表的訪問

例8-13

設(shè)已有如圖8-5所示的單向鏈表,編寫輸出鏈表的函數(shù)。

voidprint_link(structstudent*head)/*形參head為要輸出鏈表的頭指針*/{structstudent*p;p=head;while(p!=NULL){printf("%d,%6.1f\n",p->num,p->score);p=p->next; /*讓指針P指向下一個節(jié)點*/}}8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表例8-14

設(shè)已有如圖8-5所示的單向鏈表,編寫統(tǒng)計鏈表長度的函數(shù)。intlen_link(structstudent*head)/*形參head為要輸出鏈表的頭指針*/{intn=0;structstudent*p;p=head;while(p!=NULL){n++; /*累計計數(shù)*/

p=p->next; /*移動指針*/}

return(n); /*將n的值返回*/}8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表8.7.5動態(tài)存儲空間的建立和釋放

動態(tài)存儲空間的建立(1)malloc函數(shù)其函數(shù)原型為:void*malloc(unsignedintsize)其作用是在內(nèi)存的動態(tài)存儲區(qū)中分配一個長度為size的連續(xù)空間。此函數(shù)的值(即“返回值”)是一個指向分配域起始地址的指針(基類型為void)。如果此函數(shù)未能成功地執(zhí)行(例如內(nèi)存空間不足),則返回空指針(NULL)。(2)sizeof(type)運算符計算所給數(shù)據(jù)類型type的字節(jié)數(shù),主要用來計算鏈表中結(jié)點所占動態(tài)存儲空間的字節(jié)數(shù)。譬如:new=(structstudent*)malloc(sizeof(structstudent))(3)calloc函數(shù)其函數(shù)原型為:void*calloc(unsignedn,unsignedsize)其作用是在內(nèi)存的動態(tài)區(qū)存儲中分配n個長度為size的連續(xù)空間。函數(shù)返回一個指向分配域起始地址的指針;如果分配不成功,則返回NULL。用calloc函數(shù)可以為一維數(shù)組開辟動態(tài)存儲空間,n為數(shù)組元素個數(shù),每個元素長度為size。

8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表動態(tài)存儲空間的釋放

free函數(shù),其函數(shù)原型為:voidfree(void*p)其作用是釋放由p指向的內(nèi)存區(qū),使這部分內(nèi)存區(qū)能被其他變量使用。p是調(diào)用calloc或malloc函數(shù)時返回的值。free函數(shù)無返回值。

8.7.6動態(tài)鏈表的建立

所謂建立動態(tài)鏈表是指在程序執(zhí)行過程中從無到有地建立起一個鏈表,即一個一個地開辟結(jié)點和輸入各結(jié)點數(shù)據(jù),并建立起前后相鏈的關(guān)系。

8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表建立鏈表的主要步驟:1)設(shè)3個指針變量:head、p1、p2,它們都是用來指向structstudent類型數(shù)據(jù)的。structstudent*head=NULL,*p1,*p2head:頭指針變量,指向鏈表的第一個結(jié)點,用作函數(shù)返回值。p1:指向新申請的結(jié)點。p2:指向鏈表的尾結(jié)點,用P2->next=P1,實現(xiàn)將新申請的結(jié)點插入到鏈表尾,使之成為新的尾結(jié)點。2)malloc函數(shù)開辟第一個結(jié)點,并使head和p2都指向它。head=p2=(structstudent*)malloc(sizeof(structstudent));scanf("%d%f",&p2->num,&p2->score);3)再用malloc函數(shù)開辟另一個結(jié)點并使p1指向它,接著輸入該結(jié)點的數(shù)據(jù),并與上一結(jié)點相連,且使p2指向新建立的結(jié)點。建立新結(jié)點:p1=(structstudent*)malloc(sizeof(structstudent))輸入數(shù)據(jù):scanf("%d%f",&p1->num,&p1->score);與上一結(jié)點相連:p2->next=p1;

8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表4)為末結(jié)點的指針域賦值NULL(p2->next=NULL;)

8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表例8-15

建立有n個student類型結(jié)點的鏈表,n的值從鍵盤輸入,再輸出鏈表。#defineLENsizeof(structstudent) /*定義代表結(jié)構(gòu)體長度的宏*/#include<stdlib.h>#include<stdio.h>structstudent /*定義結(jié)構(gòu)體類型*/{intnum;floatscore;structstudent*next;};8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表/*main函數(shù)中,分別調(diào)用create和print函數(shù)建立和輸出鏈表*/voidmain(){intn;structstudent*head;structstudent*create(intn); /*函數(shù)聲明*/

voidprint_link(structstudent*head); /*函數(shù)聲明*/

printf("pleaseinputn\n");scanf("%d",&n);head=create(n);/*調(diào)用創(chuàng)建單鏈表函數(shù),創(chuàng)建有n個結(jié)點的單向鏈表*/

print_link(head); /*調(diào)用例8-13編寫的輸出鏈表函數(shù),輸出鏈表*/}8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表/*create(intn)函數(shù):創(chuàng)建一個具有頭結(jié)點的單鏈表,形參n值:創(chuàng)建鏈表的結(jié)點數(shù),返回值:返回單鏈表的頭指針*/structstudent*create(intn){inti;structstudent*head=NULL,*p1,*p2;head=p2=(structstudent*)malloc(LEN); /*申請一個新結(jié)點的空間*/

scanf("%d%f",&p2->num,&p2->score); /*讀入數(shù)據(jù)*/

for(i=2;i<=n;i++){p1=(structstudent*)malloc(LEN);scanf("%d%f",&p1->num,&p1->score);p2->next=p1;/*與上一結(jié)點相鏈*/

p2=p1; /*使p2指向新鏈結(jié)點*/}

p2->next=NULL;return(head);}8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表8.7.7鏈表的刪除操作

根據(jù)條件刪除一個已知鏈表中的某個結(jié)點的算法是:先查找到該結(jié)點,然后把該結(jié)點的指針域賦給其前趨結(jié)點的指針域或鏈表頭指針head。

刪除首結(jié)點

使p1指向第一個結(jié)點,用以下語句實現(xiàn)刪除首結(jié)點操作。p1=head;

head=p1->next;

free(p1);

8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表刪除其他結(jié)點

刪除鏈表的中間結(jié)點通過將下一結(jié)點和尾結(jié)點地址賦給前一結(jié)點地址來實現(xiàn),也即將要刪除的p1結(jié)點的后繼地址,放入前一結(jié)點p2的地址域(p2->next=p1->next;),同時釋放p1結(jié)點

8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表/*該函數(shù)的功能是從表頭指針為head的鏈表中刪除num域的值與形參num相等的結(jié)點,釋放該結(jié)點的存儲空間,返回該鏈表的表頭指針。*/structstudent*delete(structstudent*head,intnum){structstudent*p1,*p2;if(head==NULL)printf("listnull!\n");else{p1=head;while(p1!=NULL&&p1->num!=num)/*while循環(huán)查找刪除結(jié)點*/{p2=p1;p1=p1->next;

} /*后移一個結(jié)點*/

if(p1->num==num) /*找到了*/{if(p1==head)head=p1->next; /*刪除頭結(jié)點*/

elsep2->next=p1->next; /*刪除中間結(jié)點*/

free(p1);}elseprintf("%dnotbeenfound!\n",num);}return(head);}8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表例8-16

在例8-15建立鏈表中,刪除鏈表中結(jié)點num域的值等于輸入值del_num的結(jié)點。voidmain(){intn,del_num; /*n鏈表結(jié)點數(shù)*/

structstudent*head;structstudent*create(intn); /*函數(shù)說明*/

voidprint_link(structstudent*head);/*函數(shù)說明*/

structstudent*delete(structstudent*head,intnum);/*函數(shù)說明*/

printf("pleaseinputn\n");scanf("%d",&n);head=create(n); /*調(diào)用建立鏈表函數(shù)create,有n個結(jié)點*/

print_link(head); /*輸出刪除前的鏈表*/

printf("pleaseinputdel_num\n");scanf("%d",&del_num);head=delete(head,del_num); /*刪除鏈表num城值為del_num的結(jié)點*/

print_link(head); /*輸出刪除后的鏈表*/}8.7動態(tài)數(shù)據(jù)結(jié)構(gòu)——鏈表8.7.8鏈表的插入操作

(1)原鏈表為空表即head=NULL時,用以下語句實現(xiàn)插入操作:head=p0;p0->next=NULL;

p0是該鏈表唯一一個結(jié)點(2)在頭結(jié)點之前插入當(dāng)p0->score<=p1->score且p1→next==NULL時,若p1!=head,表示插入結(jié)點在頭結(jié)點之前。用以下語句實現(xiàn)插入操作:head=p0;p0->next=p1(3)在頭結(jié)點之后,尾節(jié)點之前插入,即中間插入當(dāng)p0->score<=p1->score,且p1<>head時,表示在頭結(jié)點之后,尾節(jié)點之前(中間結(jié)點)插入

溫馨提示

  • 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

提交評論