c语言基础教程 第九章联合和枚举.docx
《c语言基础教程 第九章联合和枚举.docx》由会员分享,可在线阅读,更多相关《c语言基础教程 第九章联合和枚举.docx(11页珍藏版)》请在冰豆网上搜索。
![c语言基础教程 第九章联合和枚举.docx](https://file1.bdocx.com/fileroot1/2022-12/12/1625f77f-9617-40bb-9434-7b510c836fe7/1625f77f-9617-40bb-9434-7b510c836fe71.gif)
c语言基础教程第九章联合和枚举
C语言基础教程9.1.1联合变量的定义和赋值
联合变量定义的形式与结构很相似,除关键字不同,其余几乎相同。
下面是一个联合模式的定义格式:
union(联合名)
{
(联合成员说明);
};
其中,union是联合的关键字。
(联合名)的命名方法同标识符,<联合成员说明》是将组成该联合的所有成员进行类型说明。
C:
语言中,几乎所有类型都作为联合的成员,包含结构变量在内。
联合变量的定义如下所示:
union<联合名)(联合变量名表);
定义一个联合变量之前要先定义一种联合模式,任何一种联合变量都是属于某种联合模
式的联合变量,这一点与结构变量很相似。
<联合变量名表)中,可以是一个联合变量名,也可是多个联合变量名,多个变量用逗号分隔。
这里的变量可以是一般联合变量,也可以是指向联合变量的指针。
例如:
uniondate
{
Charc_data;
intidata;
float f._data;
doubled_data;
};
uniondatadl,d2.*pd.
其中,anion是关键字,data是联合名,该联合有4个成员,分别作了说明dl和d2是两个联合变量,pd是一个指向联合变量的指针。
联合变量dl和d2都是具有联合名data的联合变量。
而联合变量指针pd也是指向具有data联合名的联合变量的指针。
与结构相类似,上述定义联合变量也可以写成如下形式:
uniondata
{
charc_data;
inti_data;
floatf_data;
doubled_data;
}d1,d2,*pd;
这里,也同样定义了联合变量dl和d2以及指向联合变量的指针pd。
联合变量的成员表示也与结构相似。
联合变量的成员用"·"表示,指向联合变量的指针用"一>"表示。
联合变量的赋值主要是给联合变量的各成员赋值。
例如,在上例中,对联合变量dl的几个成员赋值分别如下:
dl.c_data='a';
dl.i_data=15;
dl.f_data=10.5;
dl.b_data=87.63;
对指向联合变量的指针pd赋值与给联合变量赋值相同,只是其成员表示不同。
例如,给pd的最后一个成员赋值如下:
Pd一>d_data=97.0
由于联合变量中的若干个成员共用内存单元,即一个联合变量的所有成员具有一个相同
的内存地址值,因此,在联合变量中起作用的成员是最近一次被赋值的成员,因为一个联合变量的若干个成员共用一个内存地址,存入了新的成员值时,原来的成员值便失去意义。
如果给联合变量赋初值,只能有一个值,并且指定斌给第一个成员,而不能用多个值赋给多个成员,其原因是由于联合变量所有成员共占一个内存地址。
C语言基础教程9.1.2联合与结构的区别
前面对联合变量的定义和联合变量成员的表示以及对联合变量的赋值作了描述,可以看出联合与结构有许多相似之处,但是也指出了两者的最大区别在于联合是共址的,结构是异址的。
即联合的所有成员共同使用一个内存地址,而结构的每个成员都有自己的内存地址。
由于联合的共址特性使得它与结构产生了很大差别。
例如,在斌初值时,联合变量只能给第一个成员赋初值;不能对联合变量名赋值;不能用联合变量作函数参数,也不能用联合变量作函数的返回值,只能用指向联合变量的指针作函数参数。
下面举出两个例子说明联合变量的使用和特点。
[例9.1]分析下列程序的输出结果,进而说明联合变量的成员是共址的。
uninndata
{
charc_data;
inti_data;
floatf_data;
};
main()
{
uniandatadl;
d1.c_data='a';
dl.i_data=5;
d1.f_data=3.7;
printf("%c\t%d\t%.2f\n",dl.c._data,dl.i_data,dl.f,data);
printf("%d\n',sizeof(dl));
printf("%p\t%p\t%p\t%p\n",&dl.c_data,&dl.i_data,&dl.f.data,&dl);
}
执行该程序输出结果如下:
?
?
3.7(?
表示无意义)
4
FFD6 FFD6 FFD6 FFD6
说明:
(1)该程序中,首先定义一个联合,其名为data,它有3个成员,分别是三种不同类型。
又定义联合变量d3,并给它的三个成员分别赋值。
当使用printf()函数输出dl的三个成员的值时,前两个成员输出值是无意义的,只有最后一个成员是有意义的,其值为3.7.这说明:
某一时刻一个联合变量中只有一个成员起作用,其他成员不起作用。
(2)输出,SizeoE(dl)的值为4,这说明联合变量d1占内存4个字节。
在多个联合成员共占一个内存地址时,该地址所指向的内存空间是所有成员中占内存空间最大的成员所占的内存空间。
该例中的三个成员所占内存字节数分别为1.2和4,最大的是4,因此,联合变量dl所占内存空间为4个字节。
(3)使用printf()函数分别输出联合变量dl的三个成员的内存地址都是相同的,并且与联合变量dl的地址值也是相同的,可见联合变量各成员是共址的。
[例9.2]分析下列程序的输出结果,并指出该结果说明了什么间题。
main()
{
union{
intig[6],
chars[12];
}try;
try.ig[0]=0x4542;
try.ig[1]=0x2049;
try.ig[2]=Ox494a;
try.igt3]=0x474e;
try.ig[4]=Ox0a21;
try.ig[5]=0x0000:
prints("%s\n",try.s),
执行该程序输出如下结果:
BEI JING
说明:
该程序中定义一个无名联合,用它定义一个联合变量try,该联合有2个成员,每个成员都占内存12个字节。
程序中对try的ig成员斌了值,ig是一个int型数组,分别对它的6个元素都赋了值。
然后,程序中通过try的另一个成员。
进行输出,所输出的字符串正是try的成员所被赋值的ASCII码所对应的字符组成的。
由此可见,联合变量各个成员是共内存单元的,因此。
按某个成员赋的值,可按其另一个成员进行输出,但要求输出的类型与效据类型相一致。
C语言基础教程9.2联合的应用
由联合的特征决定了它的应用远不如结构应用那样广泛。
但是。
在有些情况下也使用联合来解决问题。
在实际应用中,常常会出现一些虽相互间排斥的情况,这时用联合就十分方便。
例如,假定某学校一些学生在校内住宿,另一些学生在校外住宿。
对于在校内和在校外住宿的学生的住址描述是不同的,可分别用下述两种结构来描述:
structoff__school
{
intstrnucm
charstrnamet[20];
charcity(20];
}
structinschool
{
charcollname[lO];
chardorm[l0];
introomnum;
};
住在校外的学生可用off_school结构来描述地址,而住在校内的学生可用in.school结构
来描述地址。
而对每个学生来说,情况是唯一的,即二舌只可选择其一。
于是,一个学生的地址
可用下述联合来描述:
unionaddress
{
structoff_schooltown;
structinschoolgown;
};
该联合中两个成员是结构变量,即结构变量可以作联合成员.相反,联合变量也可以作为结构成员,即联合与结构二者可以相互嵌套。
例如:
structstudent
{
charname[20};
intstunum;
intgrade[3];
unionaddressa;
}:
该结构中,有一个成员a是联合变量,而该联合中又有结构变量。
这便是结构和联合的定义上的嵌套。
虽然,由于联合成员是共址的,而对联合变童应用作了一些限制,不像结构变量应用得那么广泛、但是联合变量除了可以作为结构成员外。
还可以作为数组元素,即联合数组。
另外,指向联合变量的指针可以作函数参数等。
[例9.3]假定描述一个学生使用下面的内容:
学号,姓名,三门功课的成绩和住址。
其中,住址有两种情况:
住在校内和住在校外。
使用一个变量来标识一个学生住在校内或是校外,而学生住址用前面讲过的联合address来表示。
于是描述学生的结构格式如下:
structstudent
{
intstunum;
charname[20]
intgrade[3]
charoffin;
unionaddressa;
};
其中,char型变量off_in用来标识该学生是住在校内(用n表示)还是住在校外(用'f'表示).编程输人每个学生的信息,并通过姓名来查找某个学生的住址和三门成绩总和。
程序内容如下:
structoff school
{
intstrnum;
chars1rname[20];
charcity[20];
};
strurtin school
{
charcollname[10]:
chardorm[l0];
introomnum;
};
unionadclress
{
structoff.schooltown;
structin_schoolgown;
};
strsscrstudent
r
intstunum
charname[20];
intgrade[3];
charoff in;
unionaddressa;
}s[3]={{7001,"Li",{90,80,85},'f'}
{7002,"Ma",{85.95,87},'f'},
{7003,"Lu",{80,75,83},'n'}};
main()
{
inti;
charname[20];
for(i=0;i<3;i++)
{
printf("Inputaddress--");
if(s[i].off_in=='f')
{
printf("strnum,strname,city:
");
scanf("%d%s%s",&s[i].a.town.strnum.s[i].a.town.strname,
s[i].a.town.city);
}
else
{
printf("collname,dowm.roomnum:
");
scanf("%s%s%d",s[i].a.gown,collname.s[i].a.gown.dorm,
&s[i].a.gown.roomnum);
}
}
printf("Inputname:
");
scanf("%s",name)
for(i=0;i<3;i||)
{
if(Istrcmp
if(s[i].off_in=='f')
{
printf("%d,%s,%s\n",s[i].a.town.strnum,s[i].a.town.strname.
s[i].a.town.city);
printf("%d\n,s[i].grade[0]+s[i].grade[1]+s[i],grade[2]);
}
else
{
printf("%s,%s,%d\n,s[i].a.gown.collname,s[i].a,gown.dorm
s[i].a.gown.rommnum);
printf("%d\n",s[i],grade[0]+s[i].grade[1].grade[2];
}
}
}
执行该程序,屏幕上显示如下信息:
Inputaddress-strnum,strname,city:
101HaidianBeijing
Inputaddress-strnum,strname,city:
203HaidianBeijing
Inputaddress-collnum,dorm,rommnum:
Beida35d105
Inputname:
Ma
这时,屏幕上显示该程序的输出结果:
203,Haidian,Beijing
267
说明:
该程序是结构和联合相互嵌套,结构中有联合变量,联合中又有结构变量。
程序中定义的s是结构数组,它有三个元素。
开始时对每个元素的前4个成员赋了初值,然后在程序中又通过键盘输入给S的3个元素中最后一个成员赋值,由〕几该成员的值有两种形式,或者是校外地址形式,或者是校内地址形式,因此使用了下列if语句:
if(s[i].off_in='f')
满足该if条件,则按校外地址格式输入地址,否则按校内地址格式输入地址。
同样,在输出学生地址时,也有两种不同形式。
C语言基础教程9.3.1枚举变量的定义和赋值
枚举也是一种构造的数据类型,具有这种类型的变量,称为枚举变量。
枚举变量的定义形式与结构变量、联合变量有相似之处,但是枚举变量与它们都有很大的不同。
枚举是具有名字的若干个常量的有序集合,枚举变量的取值范围是该枚举表所对应的枚举符。
枚举变量被赋值以后,它实际上是一个常量,因为枚举符是具有名字的常量,而枚举变量的值只能取某一个枚举符。
因此,有人说,枚举变量是一种特殊的常量。
枚举变量在定义之前要先定义一种枚举模式,任何一枚举变量都是某种枚举模式的枚举变量。
枚举模式定义格式如下:
enum<枚举名>{(枚举表)};
其中,enum是枚举关键字,(枚举名)的命名方法同标识符。
<枚举表>是由若干个枚举符组成的,多个枚举符之间用逗号(,)分隔。
枚举符又称为枚举元素或枚举常量,它是一种标识符,而且它具有确定的int型值。
枚举变量定义格式如下:
enurn<枚举名><枚举变量名表>;
其中,(枚举变量名表》是由逗号分隔的若干个枚举变量名组成的。
例如:
ercamday{sun,Mon.Tue,Wed,The,Fri,Sac};
enumdayd1,d2;
其中,day是枚举名,Sun,Mon,""",Sat是枚举符表,它由7个枚举符组成。
dl和d2是被定义的具有day枚举模式的两个枚举变量。
dl和d2的值只能选取day的枚举符。
另外,dl和d2的定义也可以写成如一F格式:
enumday{Sun,Mon,Tue,Wed,Thu.Fri,Sat)dl,d2;
定义后枚举变量应该先赋值,然后再引用,否则无意义。
枚举变量应被赋一个它所对应的枚举符表中的一个枚举符。
例如:
d1=Sun:
d2=Fri;
这时的d1和d2两个枚举变量被赋了值,而Sun和Fri都是dl和d2所对应的枚举模式的枚举表中的枚举符,因此这是合法的。
这里必须指出一点,不能直接给枚举变量赋一个整型数值,例如,
dl=0;
这是非法的,而
dl=(enumday)0
是合法的,它等价于
dl=Sun;
因为,Sun枚举符所隐含的int型数值为0,在给枚举变量赋int型数值时,前面必须加上强制类型运算符(enuxn<枚举名>)。
枚举表中的枚举符不是变量,而是具有名字的常量,它们都各自隐含一个int型值。
在默认的情况下。
枚举表巾枚举符的值从。
开始,后一个总是比前面一个大1.例如,在上述的枚举表中,Sun的值是6,Mon的值是1,Tue是2.Wed是3,Thu是4.Fri是;Sat是6.另外,在定义枚举模式时,可以通过显式赋值的方法来确定枚举符的值。
例如:
enumday{Sun=7,Mnn=1,Tue,Wed,Thu,Fri,Sat};
这里,Sun的值是7,Mon的值是1,它们是通过显式赋值来确定其值的,Tue没有被显式赋值,它的值是前一个枚举符的值加1,即为2,同祥Web的值是3.",Sat的值是6.
下面再举一个枚举的例子。
enumcoin{penny,nickel,dime,qunrrer,halfdollar,dollar}money;
该枚举名是coin,它由6个枚举符组成一个枚举表。
money是枚举变量名,它的取值范围在该枚举表中。
例如,
money=dime;
是合法的,而
money-Fri;
是非法的,因为Fri不是money枚举变量所对应的枚举表的枚举符,而是day枚举名的枚举符,因此,任何一个枚举变量的值只能是它所对应的枚举表中的枚举符,而不能是其他枚举表中的枚举符。
C语言基础教程9.3.2使用枚举变量时应注意的事项
在编程中使用枚举变量应注意如下事项。
(1)枚举符不是整型变量。
不能在程序中对它赋以数值。
在上述day枚举例中,例如,
Mon=2;
Sat=5;
都是错误的。
枚举符是按常量处理的,称为枚举常量。
枚举符所隐含的int型值可以在定义枚举模式时对枚举表中的枚举符进行显式赋值来确定。
(2)枚举变量一般用它所对应的枚举表中的枚举符来赋值。
如果用整型值来赋值时,前面需要加上强制类型运算符,而不能直接用int值来赋值。
枚举变量的输出值是int型值,而不是字符串。
枚举表中的枚举符只是一个有名字的int型值,把它赋给枚举变量,而使枚举变量获得了其名字所隐含的int型值。
因此,输出枚举变量值时,要使用格式符%d.例如,dl是枚举名day的一个枚举变量,而被赋值为Wed,输出该变量值使用如下格式:
printf("%d\n,dl).
如果你希望输出Wed时,还需要做一些转换,其方法很多,可以用字符数组的方法,如本章后面的例子,也可以用switch语句的方法,读者可自行设计。
(3)枚举变量可以进行比较运算,比较时按其枚举符所隐含的枚举值进行。
例如,
if(dl=Tue…
if(d1 都是合法的。
另外,枚举变量可以用作函数参数和函数的返回值。
有关例子在后面章节中会看到。
使用枚举变量的好处主要是更加直观,用户可以选用一些"见名知意"的枚举符,使人看上去一目了然,使用枚举符可便于记忆。
另外,枚举变量的值受到所对应的枚举表的限制,增加数据的安全性,一旦枚举变量所得到的值超过了相应的枚举表的范围,则会出现错误信息。
枚举类型的数据在编译时作类型检查,增加了可靠性。
枚举变量的主要用途是可作为函数参数和函数返回值。
枚举变量也可以作结构的成员。
[例9.4]编一个程序,已知某天是星期几,计算出下一夭是星期几。
要求使用枚举变量。
程序内容如下:
enumday(Sun,Mon,Tue,Wed,Thu,Fri,Sat)
enumdayday_after(d)
enumd;
{
return((enumday)(((int)d+1)%7));
main()
(
enumdaydl,d2;
staticchar,name[]={"Sun","Mon"."Tue"
"Wed","Thu","Fri","Sat")
dl=Sat;
d2=day.after(d1);
print(("%s\n",name}(int)d2]);
}
执行该程序输出结果如下
Sun
(1)本例中,被调用函数的参数使用了枚举变量,井且该函数的返回值也是枚举变量。
因此,可见枚举变量可用来作函数参数和函数的返回值。
(2)枚举符是一个名字,它具有int型值。
可用它直接给枚举变量赋值,但要求是对应枚举表中的枚举符。
但是,不能使用%s格式直接输出枚举符的名字。
如果需要输出枚举符的名字时,该例是通过字符数组进行转换的。