《C語言程序設計 》課件第9章_第1頁
《C語言程序設計 》課件第9章_第2頁
《C語言程序設計 》課件第9章_第3頁
《C語言程序設計 》課件第9章_第4頁
《C語言程序設計 》課件第9章_第5頁
已閱讀5頁,還剩87頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第9章結構體、聯(lián)合體與枚舉類型9.1結構體9.2聯(lián)合體9.3枚舉類型9.4類型定義符typedef 9.1結構體

9.1.1結構體類型的定義

結構體類型是用戶自定義類型,因此要使用結構體變量就要先自行定義結構體的類型。結構體類型定義用關鍵字struct標識,形式為

struct結構體類型名

{

類型說明符成員表列;

};其中:結構體類型名是用戶為自己定義的結構體類型所起的名稱;成員表列由若干個C語言的各種數(shù)據(jù)類型的變量組成,每個變量被稱為一個成員,每個成員都是該結構體的一個組成部分。對每個成員也必須作類型說明,成員名的命名應符合標識符的命名規(guī)定。例如,在學籍管理程序中,可以定義如下結構體:

structstudent

{

intnum;

charname[20];

charsex;

floatscore;

};其中,結構體類型名為student。該結構體由4個成員組成:第一個成員為num,整型變量;第二個成員為name,字符數(shù)組;第三個成員為sex,字符變量;第四個成員為score,實型變量。9.1.2結構體變量的定義、引用及初始化

1.結構體變量的定義

在程序中不能直接使用結構體類型來編程,必須用定義好的結構體類型再定義出結構體變量,利用結構體變量進行編程。

定義結構體變量有三種方法,下面以9.1.1節(jié)中定義的student為例來加以說明。

(1)先定義結構體類型,再定義結構體變量。

例如:

structstudent

{

intnum;

charname[20];

charsex;

floatscore;

};

structstudentboy1,boy2;

這里定義了一個結構體類型student的兩個變量boy1和boy2。

(2)定義結構體類型的同時定義結構體變量。

例如:

structstudent

{

intnum;

charname[20];

charsex;

floatscore;

}boy1,boy2;

(3)直接定義結構體變量。

例如:

struct

{

intnum;

charname[20];

charsex;

floatscore;

}boy1,boy2;方法(3)與方法(2)的區(qū)別在于方法(3)中省去了結構體類型名,而直接給出結構體變量。三種方法中定義的boy1,boy2變量都具有如圖9-1所示的結構。從圖中可以看出結構體變量的各個成員所占存儲空間的地址是連續(xù)的。

如前所述,結構體的成員也可以是另一個結構體類型,稱為結構體類型嵌套。例如:

structdate

{

intmonth;

intday;

intyear;

};

struct{

intnum;

charname[20];

charsex;

structdatebirthday;

floatscore;

}boy1,boy2;圖9-1結構體變量的結構首先定義一個結構體date,該結構體由month(月)、day(日)、year(年)三個成員組成。在定義變量boy1和boy2時,其中的成員birthday被定義為data結構體類型。成員名可與程序中的其他變量同名,互不干擾。

2.結構體變量的引用

雖然一個結構體變量的各自成員的地址空間連續(xù),但在程序中對結構體變量一般不能整體引用。在ANSIC中,除了允許具有相同類型的結構體變量相互整體賦值以外,一般對結構體變量的引用(包括輸入、輸出、運算等)都是通過對結構體變量的各個成員訪問來實現(xiàn)的。

訪問結構體變量成員的一般形式為

結構體變量名.成員名例如:

(1)賦值運算:

boy1.num=1001;

(2)如果結構體類型中嵌套結構體,則對結構體變量成員的訪問可以通過“.”運算符,逐級引用到最低級:

boy1.birthday.month=3;

(3)輸入運算:

scanf("%s",);

(4)輸出運算:

printf("%c",boy1.sex);

(5)相同類型的結構體變量之間可以互相賦值:

boy2=boy1;

除了整體賦值,不能將一個結構體變量作為一個整體進行訪問。

【例9.1】

在學籍管理程序中,輸入一個學生的學號、姓名、性別以及三門課的成績,并輸出該學生的信息及平均成績。

程序如下:

main()

{

structstudent

{

intnum;

charname[20];

charsex;

floatscore[3];

};

structstudentboy1;

inti;

floatavg=0;

printf(“請輸入學生的學號、姓名和性別:\n”);

scanf(“%d%s%c”,&boy1.num,,&boy1.sex);

printf(“請輸入學生的三門課成績:\n”);

for(inti=0;i<3;i++)

scanf(“%f”,&boy1.score[i]);/*輸入boy1變量的score數(shù)組成員*/

printf(“學生信息:\n”);

printf(“學號=%d,姓名=%s,性別=%c\n”,boy1.num,,boy1.sex);

for(inti=0;i<3;i++)

{

printf(“第%d門課成績:%f”,i+1,boy1.score[i]);

avg+=boy1.score[i]; /*累加boy1變量的score數(shù)組成員*/

}

printf("\n平均成績:%f",avg/3);

}

3.結構體變量的初始化

和其他類型變量一樣,對結構體變量可以在定義時進行初始化賦值。初始化格式如下:

存儲類別struct結構體名

{成員表}結構體變量={初始化數(shù)據(jù)表};

【例9.2】

定義一個有學號、姓名、性別和某門課成績的結構體,對其變量進行初始化,進行結構體變量之間的賦值,并對結構體變量的各個成員的值進行輸出。

程序如下:

main()

{

structstu/*定義結構體*/

{

intnum;

char*name;

charsex;

floatscore;

}boy2,boy1={102,“ZhangPing”,‘M’,78.5};

boy2=boy1;

printf(“Number=%d\nName=%s\n”,boy2.num,);

printf("Sex=%c\nScore=%f\n",boy2.sex,boy2.score);

}

初始化數(shù)據(jù)表中的數(shù)據(jù)與結構體變量中的成員類型對應。9.1.3結構體數(shù)組的定義

如果有若干具有相同結構體類型的數(shù)據(jù)要進行處理,我們需定義基類型為相應結構體類型的數(shù)組來描述數(shù)據(jù)。這樣的數(shù)組稱為結構體數(shù)組。例如:學籍管理通常是對一批學生進行管理,一個學生對應一個結構體變量,一批學生則需要使用結構體數(shù)組。

定義結構體數(shù)組的方法有三種,分別對應三種定義結構體變量的方法,只需在結構體變量后定義數(shù)組的長度即可。例如:

structstudent

{

intnum;

char*name;

charsex;

floatscore;

};

structstudentstu[5];定義了一個結構體數(shù)組stu,共有五個元素,stu[0]~stu[4],且每個數(shù)組元素都具有structstudent的結構形式。

對結體構數(shù)組可以作初始化賦值。例如:

structstudent

{

intnum;

charname[20];

charsex;

intage;

floatscore;

charaddr[30];

}stu[2]={{10101,"LiLin",'M',18,87.5,"103BeijingRoad"},

{10102,"ZhangFun″,'M',19,99,"130ShanghaiRoad"}};

當對全部元素作初始化賦值時,也可不給出數(shù)組長度。

【例9.3】計算五個學生的平均成績和不及格的人數(shù)。

程序如下:

main()

{

structstudent

{

intnum;

charname[20];

charsex;

floatscore;

charaddr[30];

};

structstudentstu[5];

inti,c=0;

floatave,s=0;

for(i=0;i<5;i++)

{

printf(“請輸入學生的信息:”);

scanf(“%d%s%c%f%s”,&stu[i].num,stu[i].name,&stu[i].sex,&stu[i].score,stu[i].addr);

}

for(i=0;i<5;i++)

{

s+=stu[i].score;

if(stu[i].score<60)c+=1;

}

printf("s=%f\n",s);

ave=s/5;

printf("average=%f\ncount=%d\n",ave,c);

}

說明

stu是結構體數(shù)組。在循環(huán)中,stu[i]?代表stu中的每個元素,但stu[i]?本身是結構體變量,要訪問其中的成員,則需要用“.”運算符。

【例9.4】編寫對候選人得票的統(tǒng)計程序。設有三個候選人,每次輸入一個得票的候選人的名字,要求最后輸出各人得票結果。

程序如下:

#include<string.h>

#include<stdio.h>

structperson

{

charname[20];

intcount;

}leader[3]={"Li",0,"Zhang",0,"Fun",0};

voidmain()

{

inti,j;

charleader_name[20];

for(i=1;i<=10;i++)

{

scanf(“%s”,leader_name);

for(j=0;j<3;j++)

if(strcmp(leader_name,leader[j].name)==0)

leader[j].count++;

}

printf(“\nResoult:\n”);

for(i=0;i<3;i++)

printf(“%5s:%d\n”,leader[i].name,leader[i].count);

}9.1.4結構體作為函數(shù)參數(shù)

結構體作為函數(shù)參數(shù)與數(shù)組作為函數(shù)參數(shù)類似,有結構體變量的成員作為函數(shù)參數(shù)和結構體變量作為函數(shù)參數(shù)兩種情況。

1.結構體變量的成員作為函數(shù)參數(shù)

結構體變量的成員作為參數(shù),對應的形參應是與作為實參的結構體成員類型相同的變量。

【例9.5】定義一個結構體類型,包括學號、姓名和三門課的成績,編程實現(xiàn)對某學生信息的初始化,并輸出其平均成績。程序如下:

floataverage(floatx,floaty,floatz)

{

return(x+y+z)/3;

}

voidmain()

{

floatavg=0;

structstudent

{

intnum;

charname[20];

floatscore[3];

};

structstudentstu={1001,“sdas”,89.0,67.5,80.0};

avg=average(stu.score[0],stu.score[1],stu.score[2]);

printf(“平均成績:%f”,avg);

}

對比程序:

floataverage(float*x,intn) /*x指向score數(shù)組*/

{

floats=0;

intj;

for(j=0;j<n;j++)

s+=*(x+j);

returns/n;

}

voidmain()

{

floatavg=0;

structstudent

{

intnum;

charname[20];

floatscore[3];

};

structstudentstu={1001,"sdas",89.0,67.5,80.0};

avg=average(stu.score,3);

printf("平均成績:%f",avg);

}

2.結構體變量作為函數(shù)參數(shù)

用結構體變量作實參,對應的形參應是與作為實參的結構體變量同類型的結構體變量。

【例9.6】設計一個對結構體變量的成員值進行輸出的函數(shù)。要求在主函數(shù)中定義結構體變量并對其初始化,以結構體變量作實參,調用函數(shù)輸出結構體變量的成員值。

程序如下:

#include<stdio.h>

#include<string.h>

structstudent

{

intnum;

charname[20];

floatscore;

};

voidprint(structstudentstu)

{

printf(“num:%d\nname:%s\nscore:%5.1f\n”,stu.num,,stu.score);

}

voidmain()

{

structstudentstu;

stu.num=12345;

strcpy(,“LiLi”);

stu.score=67.5;

print(stu);

}9.1.5指針與結構體

1.指向結構體變量的指針

當用一個指針變量指向一個結構體變量時,這個指針變量被稱為結構體指針變量。一個結構體變量的起始地址就是這個結構體變量的指針。指針指向結構體變量實際上就是指向結構體變量的首地址。結構體指針變量的基類型必須與結構體變量的類型相同。

結構體指針變量說明的一般形式為

struct結構體類型名*結構體指針變量名

例如:

structstudentstu,*pstu;定義了student這個結構體類型的變量stu和一個指向student的指針變量pstu。若要使結構體指針指向對應的結構體變量,則應將結構體變量的首地址賦予該指針變量。例如:

pstu=&stu;

指針變量指向結構體變量后,可采用以下三種方式訪問該結構體變量的成員:

結構體變量.成員名

(*p).成員名

p->成員名這三種用于表示結構體成員的形式是完全等效的。其中“指向”運算符由兩個字符“-”和“>”組成,運算符優(yōu)先級與“?.?”運算相同。

例如:

=“ZhangLi”;

(*pstu).sex=‘M’;

pstu->score=71.0;

2.指向結構體數(shù)組的指針

指針變量可以指向一個結構體數(shù)組,這時結構體指針變量的值是整個結構體數(shù)組的首地址。結構體指針變量也可指向結構體數(shù)組的一個元素,這時結構體指針變量的值是該結構體數(shù)組元素的首地址。

設p為指向結構體數(shù)組的指針變量,則p也指向該結構體數(shù)組的0號元素,p+1指向1號元素,p+i則指向i號元素。這與普通數(shù)組的情況是一致的。

【例9.7】定義一個student結構體數(shù)組,成員包括學號、姓名、性別、年齡,分別對三個學生的數(shù)據(jù)進行初始化后,通過指針訪問該數(shù)組,輸出每個學生的信息。程序如下:

#include<stdio.h>

voidmain()

{

structstudent

{

intnum;

charname[20];

charsex;

intage;

};

structstudentstu[3]={{10101,“LiLin”,‘M’,18},{10102,“ZhangFun”,‘M’,19},{10104,“WangMin”,‘F’,20}};

structstudent*p;

p=&stu;

/*p指向stu數(shù)組的首地址*/

printf(“No.NameSexAge\n”);

for(p=stu;p<stu+3;p++)

{

printf(“輸出學生信息:\n”);

printf("%5d%-20s%2c%4d\n",(*p).num,p->name,p->sex,p->age);

/*通過指針運算符訪問結構體變量的每一個成員*/

}

}

說明

如果p的初值為stu,即指向第一個元素,則“(++p)->num”表示先使p自加1,然后得到它指向的元素中的num成員值(即10102);“(p++)->num”表示先得到p->num的值(即10101),然后使p自加1,指向stu[1]。9.1.6結構體指針變量作為函數(shù)參數(shù)

在ANSIC標準中允許用結構體變量作為函數(shù)參數(shù)進行整體傳送,但是這種傳送要將全部成員逐個傳送,特別是成員為數(shù)組時將會使傳送的時間和空間開銷很大,嚴重地降低了程序的效率。因此最好的辦法就是使用指針,即用指針變量作為函數(shù)參數(shù)進行傳送。這時由實參傳向形參的只是地址,從而減少了時間和空間的開銷。

【例9.8】計算一組學生的平均成績和不及格人數(shù)(用結構體指針變量作為函數(shù)參數(shù)編程)。程序如下:

structstu

{

intnum;

char*name;

charsex;

floatscore;}boy[5]={

/*對boy數(shù)組進行初始化*/

{101,“Liping”,‘M’,45},

{102,“Zhangping”,‘M’,62.5},

{103,“Hefang”,‘F’,92.5},

{104,“Chengling”,‘F’,87},

{105,“Wangming”,‘M’,58},

};

main()

{

structstu*ps;

voidave(structstu*ps);

ps=boy;

ave(ps);

/*實際傳遞的是boy數(shù)組的首地址*/

}

voidave(structstu*ps)

{

intc=0,i;

floatave,s=0;

for(i=0;i<5;i++,ps++)

{

s+=ps->score;

/*通過指針方式訪問boy數(shù)組的每個元素*/

if(ps->score<60)c+=1;

}

printf("s=%f\n",s);

ave=s/5;

printf("average=%f\ncount=%d\n",ave,c);

}

說明

在主函數(shù)中,ps是指向boy數(shù)組的指針,用ps作為實參傳遞的是boy數(shù)組的首地址。

在ave函數(shù)中,形參ps雖與實參同名,但與實參ps是兩個變量,在接收了實參傳遞的值后,也指向boy數(shù)組。9.1.7鏈表

1.鏈表的概念

當處理一批相同類型的數(shù)據(jù)時,常常用到數(shù)組,但數(shù)組在使用時有一些弊端。例如:數(shù)組的大小在定義時要事先規(guī)定,不能在程序中進行調整,這樣,程序設計時在數(shù)據(jù)量不定的情況下,只能定義數(shù)組的最大上限,當數(shù)據(jù)量小于最大上限值時,有相當一部分存儲空間被浪費了;另外,數(shù)組結構在內存中占有連續(xù)的存儲空間,當數(shù)組數(shù)據(jù)量很大時,對內存的要求較高,有時甚至難以滿足。因此,如果能在程序運行過程中根據(jù)數(shù)據(jù)量的多少動態(tài)地申請內存空間,就可以解決上述問題。鏈表是最基本的一種動態(tài)數(shù)據(jù)結構。鏈表中的每一個元素除了需存放數(shù)據(jù)本身外,還有一個數(shù)據(jù)項專門用于存放相鄰元素的地址,如圖9-2所示。鏈表中的每一個“塊”都被稱為一個結點。除head以外的每一個結點都是一個結構體變量。圖9-2鏈表示意圖從圖9-2中可知:

(1)鏈表中的第一個結點是head結點,也被稱為“頭結點”,它位于鏈表的首部,是一個指針變量,用于存放第一個元素的地址。

(2)鏈表中其余的結點都分為兩個域:一個是數(shù)據(jù)域,用于存放各種實際的數(shù)據(jù),如學號num,姓名name,性別sex和成績score等;另一個是指針域,用于存放下一結點的首地址。鏈表中的每一個結點都是同一種結構類型。

(3)鏈表中最后一個結點的指針域為空指針NULL。NULL表示鏈表結束。NULL是一個符號常量,在stdio.h頭文件中定義為0。

2.鏈表的基本操作

鏈表的基本操作主要有建立鏈表、查找與輸出鏈表、插入結點和刪除結點。建立鏈表的作用是在內存中建立一個如圖9-2所示的數(shù)據(jù)結構,它是鏈表編程的基礎。查找鏈表是一個循環(huán)的過程,即從鏈表的第一個元素開始順序地查找每一個結點的數(shù)據(jù),以得到想要的信息,并加以輸出。插入結點與刪除結點是動態(tài)地為鏈表增加或刪除結點的操作,也正是鏈表動態(tài)性的體現(xiàn)。

1)建立鏈表

首先要定義鏈表中結點的數(shù)據(jù)類型。鏈表的結點是結構體變量,而且這種結構體變量必須分為兩個域:數(shù)據(jù)域(用于存放數(shù)據(jù))和指針域(用于存放鏈表中下一結點的首地址)。因此鏈表結點的類型定義如下:

structstu

{intnum;

intscore;

structstu*next;

}在上述定義中,前兩項成員是結點的數(shù)據(jù)域,第三項成員是結點的指針域。因為鏈表中所有結點都是同一類型的結構體變量,所以指針域部分的成員只能是指向自身的指針。同時,鏈表的head指針也必須是指向該類型結構體變量的指針。建立鏈表的過程如下:

(1)使用malloc函數(shù)申請內存空間,若系統(tǒng)響應此分配請求,則返回所分配空間的首地址。

(2)為新結點成員賦值。

(3)將新結點加入到鏈表的末尾。此時要分兩種情況處理:第一種,本結點加入前,若鏈表為空,即head=NULL,則加進去的結點p既是鏈表的最后一個結點,也是鏈表的第一個結點,因此要修改head的值;第二種,本結點加入前,鏈表中已有結點,這時應把結點p加到鏈表尾部。

【例9.9】建立一個鏈表,用于存放若干學生的學號、姓名和考試成績。

程序如下:

main()

{

structstu

{

intnum;

charname[20];

floatscore;

structstu*next;

};

structstu*head=NULL,*tail=NULL,*this;

intn,i;

printf("請輸入學生個數(shù):");

scanf("%d",&n);

for(i=0;i<n;i++)

{

this=(structstu*)malloc(sizeof(structstu)); /*動態(tài)申請內存空間,并將申請到的空間地址賦值給this指針*/

printf("請輸入學號,姓名和成績:");

scanf("%d,%s,%f",&this->num,this->name,&this->score);

this->next=NULL;

/*當前結點的指針域賦值為空*/

if(head==NULL)

{head=this;tail=this;}

else

{tail->next=this;tail=this;}

}

}

說明

(1)首先將鏈表的頭指針head和尾指針tail賦值為NULL,表示鏈表沒有任何結點,是空鏈表。

(2)在循環(huán)中,用malloc函數(shù)申請大小為sizeof(structstu)的內存空間,并將申請到的空間的首地址賦值給this指針。

(3)為新申請結點的數(shù)據(jù)域賦值后,需要將當前結點鏈入鏈表。如果此時head指針為NULL,說明鏈表尚無任何結點,所以head=this將頭結點指向this結點,tail=this將尾指針也指向this結點,如圖9-3(a)所示。

(4)如果當前結點鏈入鏈表時,鏈表上已有結點,則執(zhí)行tail->next=this將已有鏈表尾結點的指針域指向this結點,如圖9-3(b)所示,再執(zhí)行tail=this,將尾指針指向當前this結點,如圖9-3(c)所示。圖9-3鏈表的生成

2)查找與輸出鏈表

例9.9中已經將學生的數(shù)據(jù)存儲在鏈表中了,要將輸入的數(shù)據(jù)顯示出來,就必須對鏈表進行遍歷。所謂遍歷,就是從頭結點開始依次訪問鏈表中的每個結點,這是一個循環(huán)的過程。鏈表的遍歷和輸出的實現(xiàn)如下:

this=head;

while(this!=NULL)

{

printf(“%d,%s\n”,this->num,this->name);

this=this->next;

}在循環(huán)中將this指針所指結點的數(shù)據(jù)域輸出后,this=this->next語句將this指針后移到下一個結點。但若this結點已是尾結點,則this=this->next語句執(zhí)行后,this指針將為空,循環(huán)結束。

3)插入結點

插入結點就是在鏈表中添加新的結點,添加既可在鏈表尾部進行,又可在鏈表的任意兩個結點之間進行。

如圖9-4(a)所示,結點c將要插入鏈表的p指針和q指針所指的結點之間,插入過程分兩步進行。

第一步是將c結點的指針域指向q所指結點的首地址,而q所指結點的首地址存儲在p結點的指針域,如圖9-4(b)所示,實現(xiàn)語句為

this->next=p->next;

第二步是將p結點的指針域指向c結點的首地址,如圖9-4(c)所示,實現(xiàn)語句為

p->next=this;圖9-4插入結點

4)刪除結點

刪除結點是指從鏈表中移除指定的結點。如圖9-5(a)所示,從鏈表中刪除this指針所指的結點。this指針所指結點是p指針所指結點的后繼。因此,刪除this指針所指的結點實際上是將p指針所指結點的指針域改為指向this指針的后繼。如圖9-5(b)所示,實現(xiàn)刪除結點的語句為

p->next=this->next;圖9-5刪除結點從圖9-5(b)中可以看出,被刪除的this指針所指結點此時并未真正“消失”,但是在遍歷鏈表時已經不可能再訪問到this指針所指結點,因為在訪問p所指結點時,從其指針域得到的地址已指向了this的后繼結點。this指針所指結點要真正“刪除”,還必須被釋放,其實現(xiàn)語句為

free(this);

【例9.10】建立一個鏈表,存放十名學生的學號、姓名和三門課的考試成績。要求:將其中所有平均成績不合格的學生的數(shù)據(jù)刪除。

程序如下:

main()

{

structstu

{

intnum;

charname[20];

floatscore[3];

structstu*next;

};

structstu*head=NULL,*tail=NULL,*this,*p;

inti,j;

floatave;

for(i=0;i<10;i++)

{

this=(structstu*)malloc(sizeof(structstu));

printf("請輸入學號,姓名:");

scanf("%d,%s",&this->num,this->name);

printf("請輸入三門課的考試成績:");

for(j=0;j<3;j++) /*在循環(huán)中輸入三門課的考試成績*/

scanf("%f",&this->score[j]);

this->next=NULL;

if(head==NULL)

{head=this;tail=this;}

else

{tail->next=this;tail=this;}

}

/*鏈表建立完成*/

for(this=head;this!=NULL;p=this,this=this->next)

{

ave=0;

for(j=0;j<3;j++)

ave+=this->score[j];

if(ave/j<60.0)

{

if(this==head) /*判斷是否是刪除鏈表的第一個結點*/

{

head=this->next;

/*若刪除鏈表的第一個結點,需要將head指針的內容直接指向鏈表的原第二結點*/

}

else

{

p->next=this->next; /*若刪除鏈表的其他結點,需要將該結點的前繼指針的內容直接指向該結點的后繼結點*/

}

free(this);

}

}

} 9.2聯(lián)合體

聯(lián)合體是C語言提供的另一種組織數(shù)據(jù)對象的機制。聯(lián)合體和結構體很相似,由幾個類型相同或不同的成員組合而成,其中每個成員有一個名字。但是結構體的成員在結構體變量內部是順序排列的,每個成員的存儲空間地址連續(xù)。一個聯(lián)合體變量的所有成員共享同一片存儲區(qū),因此這種變量在每個時刻只能保存它的某一個成員的值。

1.聯(lián)合體類型及變量定義

聯(lián)合體聲明在形式上與結構體聲明類似,用關鍵字union標識。下面是一個例子,這里聲明了一個聯(lián)合體,同時定義了一個聯(lián)合體變量:

uniondata

{

intn;

doublex;

charc;

};

uniondatau1;圖9-6聯(lián)合體變量的內存分配在u1中,整型變量i、雙精度浮點型變量x和字符變量c共用同一內存空間。但這三種變量所占的存儲單元個數(shù)各不相同,在編譯時,按照u1成員所占最大存儲單元個數(shù)分配存儲空間,如圖9-6所示。聯(lián)合體變量在每個時刻只能保存它的某一個成員的值,或者存儲一個整型數(shù),或者存儲一個雙精度浮點型數(shù),或者存儲一個字符。

2.聯(lián)合體變量的初始化及引用

聯(lián)合體變量也可以在定義時直接初始化,但這種初始化只能對聯(lián)合體變量的第一個成員進行。例如,定義了兩個聯(lián)合體變量,并對它們做了初始化:

uniondataul={3},u2={5};

因為u1、u2變量的第一個成員是整型變量n,所以在對u1、u2初始化時只能賦值為整型量。

允許用已有的聯(lián)合體變量去初始化局部定義的相同類型的聯(lián)合體變量。聯(lián)合體變量的使用方式與結構體變量的一樣,也可以進行整體賦值、成員訪問、取地址等。對聯(lián)合體成員訪問的形式與對結構體成員訪問的形式一樣。下面是使用聯(lián)合體成員的幾個例子:

printf("%d",u1.n);

u1.c="\n";

scanf("%c",&u1.c);

u1.n=u1.n+1;若存在指針指向聯(lián)合體變量,可以用如下方式訪問聯(lián)合體變量的成員:

uniondatau1,*pu;

pu=&u1;

printf("%d",pu->n);

pu->c="\n";

使用聯(lián)合體變量的基本原則是:當聯(lián)合體變量中有多種不同類型的成員時,任何時候只能按照其中一種成員的類型來訪問聯(lián)合體變量。也就是最近一次對這個聯(lián)合體變量進行賦值時把它當作什么類型對待,取值時也應該采用同樣的方式(通過同樣的成員訪問取值)。

【例9.11】

某校建立一個人員登記表,記錄人員的姓名、職業(yè),若職業(yè)是教師,則需要記錄其工資,若職業(yè)是學生,則記錄其籍貫。編程對學校人員數(shù)據(jù)進行輸入,并輸出。

程序如下:

#defineN20

main()

{

structper

{

charname[10];

charjob;

union

{

floatsalary;

charaddr[30];

}category;

};

structperperson[10];

inti;

for(i=0;i<N;i++)

{scanf(“%s%c”,person[i].name,&person[i].job);

if(person[i].job==‘t’) /*若此項輸入為t,表明該人身份是教師*/

scanf(“%f”,&person[i].category.salary); /*輸入工資*/

elseif(person[i].job==‘s’)

scanf("%s",person[i].category.addr); /*輸入地址*/

elseprintf(“inputerror!”);

}

printf(“\n”);

printf(“Namejobclass/position\n”);

for(i=0;i<N;i++)

{if(person[i].job==‘t’)

/*判斷人員的身份是否是教師*/

printf(“%s%c%f”,person[i].name,&person[i].job,person[i].category.salary);

else

printf("%s%c%s",person[i].name,&person[i].job,person[i].category.addr);

/*若不是教師,則第三項數(shù)據(jù)記錄的是住址,用%s控制字符輸出*/

}

}

9.3枚舉類型

在實際問題中,有些變量的取值被限定在一個有限的范圍內。例如,一個星期只有七天,一年只有十二個月,一個班每周有六門課程等。如果把這些量說明為整型、字符型或其他類型,顯然是不妥當?shù)?。為此,C語言提供了一種稱為“枚舉”的類型。在枚舉類型的定義中列舉出所有可能的取值,被說明為該枚舉類型的變量其取值不能超過定義的范圍。應該說明的是,枚舉類型是一種基本數(shù)據(jù)類型,而不是一種構造類型,因為它不能再分解為任何基本類型。

1.枚舉類型的定義和枚舉變量的說明

1)枚舉類型的定義

枚舉類型定義的一般形式為

enum枚舉名{枚舉值表};

在枚舉值表中應羅列出所有可用值,這些值也稱為枚舉元素。

例如:

enumweekday{sun,mon,tue,wed,thu,fri,sat};

該枚舉名為weekday,枚舉值共有7個,即一周中的七天。凡被說明為weekday類型的變量,其取值只能是七天中的某一天。

2)枚舉變量的說明

如同結構體和聯(lián)合體一樣,枚舉變量也可用不同的方式說明,即先定義后說明、同時定義說明或直接說明。

要說明變量a、b、c為上述的weekday類型變量,可采用下述任一種方式:

enumweekday{sun,mon,tue,wed,thu,fri,sat};

enumweekdaya,b,c;

或者為

enumweekday{sun,mon,tue,wed,thu,fri,sat}a,b,c;

或者為

enum{sun,mon,tue,wed,thu,fri,sat}a,b,c;

2.枚舉類型變量的賦值和使用

枚舉類型在使用中有以下規(guī)定:

(1)枚舉值是常量,不是變量,不能在程序中用賦值語句再對它賦值。例如,對weekday的元素再作以下賦值:

sun=5;

mon=2;

sun=mon;

都是錯誤的。

(2)枚舉元素本身由系統(tǒng)定義了一個表示序號的數(shù)值,從0開始順序定義為0,1,2,…,如在weekday中,sun的值為0,mon的值為1,…,sat的值為6。

【例9.12】用枚舉類型表示一周的七天,定義三個變量分別表示周日、周一和周四,并對以上三個變量進行輸出。

程序如下:

main()

{

enumweekday

{sun,mon,tue,wed,thu,fri,sa

溫馨提示

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

評論

0/150

提交評論