【文档说明】C语言程序设计基础-[110页]课件.ppt,共(110)页,2.284 MB,由小橙橙上传
转载请保留链接:https://www.ichengzhen.cn/view-44507.html
以下为本文档部分文字说明:
第9章用户可建立的数据类型——复杂数据的表示与处理第9章用户可建立的数据类型——复杂数据的表示与处理9.1结构体9.2共用体9.3枚举类型9.4用户自定义数据类型名称9.5用结构体和指针处理链表实训任务十七熟悉结构体、共用体数
据类型的表示与使用实训任务十八学习复杂数据表示处理的编程方法第9章用户可建立的数据类型——复杂数据的表示与处理9.1结构体9.1.1结构体类型与结构体变量的定义1.先定义结构体类型,再定义结构体变量定义结构体类型的一般形式
为struct结构体类型名{类型成员名1;类型成员名2;„类型成员名n;};第9章用户可建立的数据类型——复杂数据的表示与处理其中,“struct”为结构体类型定义关键字,是结构体类型的标识符。“结构体类型名”是所定义结构体的类型名称,这个名
字由用户命名,其命名同变量名、数组名一样,要符合C语言的标识符命名规则。用户可以用该类型名来定义结构体变量。花括号中定义该结构体类型所包含的成员,即成员的类型、名称及其顺序关系。成员名的命名规则与标识符命名规则相同。成员
类型可以是基本类型或者任何在该结构体类型之前已经定义过的自定义类型。第9章用户可建立的数据类型——复杂数据的表示与处理结构体类型的定义仅是声明了一种数据对象的结构类型,仅表示一种抽象结构,并不代表具体的数据对象,编译系统也不分配存储空间
,不能在程序中引用。要使所定义的结构体类型代表一个数据对象,需定义结构体类型变量。定义结构体类型变量的一般方式为struct结构体类型名变量名;其中,“struct结构体类型名”代表一种结构体类型,其后的变量名就被定义为可表示该结构体类型的变量,变量表示具
有该结构体的实体对象,编译系统给结构体变量按结构体成员顺序与类型分配存储空间。第9章用户可建立的数据类型——复杂数据的表示与处理“date”是结构体类型的名称,year、month和day分别是整型数据成员的名称,表
示日期中的年、月、日。例如,定义表示日期的结构体类型:structdate{intyear;intmonth;intday;};第9章用户可建立的数据类型——复杂数据的表示与处理定义了结构体类型之后,就可以用该类型来
定义结构体变量。如:structdatedate1;“date1”是被定义为表示日期类型的结构体变量。其存储结构是连续分配3个整型数据的单元,一个整型数据占4个字节,共占12个字节的存储空间。结构体类型定义中,成员类型可以是已经定义过的任何一种数据对象的类型。例如,在
定义了日期结构体类型的基础上,可定义一个学生信息的结构体类型:第9章用户可建立的数据类型——复杂数据的表示与处理structstudent{longnum;//学号charname[20];//姓名charsex;//性
别structdatebirthday;//出生日期,已经定义的结构体类型floatscore;};第9章用户可建立的数据类型——复杂数据的表示与处理学生结构体类型定义中包含日期结构体成员birthd
ay,即结构体类型可以嵌套定义。但是,结构体不允许递归定义,即结构体的成员不能为该结构体的变量。如,下面的定义是非法的:structerror{longnum;charname[20];structerrora;//成员a定义非法};第9章用户可建立的数据类型——复杂数据的
表示与处理在定义了“student”结构体类型的基础上,可以定义该结构体类型的变量:structstudentstudent1,student2;从上述可以看出,由一个结构体类型可以定义多个结构体变量。2.在定义结构体类型的同时定义结构体变量该方式定义的一般形式为str
uct结构体类型名{类型成员名1;类型成员名2;„类型成员名n;}结构体变量名表;第9章用户可建立的数据类型——复杂数据的表示与处理在定义结构体类型的花括号外直接定义变量,可以定义一个变量,也可以定义多
个变量。定义多个变量时,变量之间要用逗号分隔。例如:structpeople{charname[10];//姓名intage;//年龄charsex[2];//性别chardepart[20];//单位ch
arduty[10];//职务}person1,person2;定义了人的基本信息的结构类型“structpeople”,同时定义了两个结构体变量person1,person2。第9章用户可建立的数据类型——复杂数据的表示与处理3.直接定义结构体类型变量该方式定义的一般形式
为struct{类型成员名1;类型成员名2;„类型成员名n;}结构体变量名表;第9章用户可建立的数据类型——复杂数据的表示与处理显然,这种定义方式是在第2种定义方式中去掉结构类型名,其他定义内容完全相同。例如:struct{char
name[10];//姓名intage;//年龄charsex[2];//性别chardepart[20];//单位charduty[10];//职务}person1,person2;定义的效果与方式2相同。第9章用户可建立的数据
类型——复杂数据的表示与处理从上述可知,定义结构体类型的目的是定义结构体变量,只有结构体变量才能存储和处理结构体数据,前两种方式定义了结构体类型名称,可以使用这种结构体类型名称来定义新的结构体变量。第3种定义方
式,没用结构体类型名,无法利用结构体类型名来定义新的结构体变量。结构体成员可以与程序中的其他变量同名,两者代表不同对象,互不影响。结构体的定义可以放在函数内,也可以放在函数外。在函数内定义的结构体只能在函数内使用(即局部数据对象)。在函数外定义的结构体可以在定义点之
后的所有函数内使用(全局数据对象)。第9章用户可建立的数据类型——复杂数据的表示与处理9.1.2结构体变量的初始化如何给结构体变量提供初始数据?定义了结构体变量后,系统按成员的顺序和类型给其分配存储空间,但成员没有指定的数据
。对结构体提供数据是针对成员来进行的,也就是说,不能对结构体整体进行,这与数组类似。对结构体成员提供数据有两种方式,一种是在定义结构体变量时提供初始值,称为初始化;还有一种是在程序运行中,通过赋值操作给成员提供值。一般在定义结构体变量时,
需进行初始化。结构体变量初始化的方式是:按结构体成员的顺序和类型分别提供初始数据。第9章用户可建立的数据类型——复杂数据的表示与处理例如,对前面定义的学生结构体变量初始化如下:structstudentstudent1={0103208,"liuxi
qiao",'w',{1983,9,17}};给结构体变量赋初值要用花括号将所有成员数据括起来。在花括号中要按成员顺序提供初始数据,数据类型要与定义的成员类型一致。例如“姓名”成员是字符数组,可以通过字符串提供初值,也可以按字符数组元素的方式提供初值。“出生日期”成员是一个结构体类型,要按定
义的日期结构体来提供初值,其年、月、日数据用花括号括起来。第9章用户可建立的数据类型——复杂数据的表示与处理9.1.3结构体成员的引用如何引用结构体变量中的数据?系统把结构体变量看作一个数据对象,给其分配数据空间,按成员的顺序和类型连续存储数据,但对结构体变量的数据不能整体引
用,只能按成员来引用。结构体数据的引用方式与数组数据的引用方式类似。结构体成员引用的形式为结构体变量名.成员名其中,“.”是C语言的一种运算符,称为“取成员运算符”。“.”的优先级是C语言中优先级最高的运算符,具有左结合性(参见附录C)。第9章用户可建立的数据类型
——复杂数据的表示与处理例如,前面定义的一个学生信息的结构体变量,student1.num表示学号成员数据项。如果成员又是一个结构体类型,则要分层用成员运算符,一级一级地找到最基本的成员。例如,要引用
一个学生信息的结构体变量中的出生日期数据,要分别采用如下的引用形式:student1.birthday.yearstudent1.birthday.monthstudent1.birthday.day不能用student1.birthday来引用出生日期数据。第9章用户可建立的数据
类型——复杂数据的表示与处理可以对结构体变量中的成员进行输入、输出、赋值、运算等操作。对结构体成员输入数据,要取成员地址。例如:scanf("%ld",&student1.num);一个成员变量可以像基本类型变量
一样进行相应的运算。例如:sum=student1.age+student2.age;age++;第9章用户可建立的数据类型——复杂数据的表示与处理例9.1定义一个学生成绩表的数据结构,学生信息包含学号、姓名、出生日期,有5门课成绩,从键盘输入数据,求出学生总分,输出学生数据和总分。编
程思路:学生成绩表包含许多学生数据,每个学生具有相同的数据结构,属于典型的结构体类型数据。先定义学生数据结构,再定义学生数据结构的变量。学生信息的输入和处理要针对成员数据来进行。第9章用户可建立的数据类型——复杂数据的表示与处理#includ
e"stdio.h"structdate//定义学生出生日期结构{intyear;intmonth;intday;};structstudent//定义学生数据结构{longnum;charname[20];structdatebirthday;floatscore[5];};第9章用户可
建立的数据类型——复杂数据的表示与处理voidmain(){inti;floatsum=0;structstudents;//定义学生数据结构变量printf("s.num:");scanf("%ld",&s.num);printf("s.name:");scanf("%s",s.name);
printf("birthday.yearbirthday.monthbirthday.day:");scanf("%d",&s.birthday.year);scanf("%d",&s.birthday.month);scanf("%d",&s.birthday.day);fo
r(i=0;i<5;i++)//循环输入一个学生5门课成绩第9章用户可建立的数据类型——复杂数据的表示与处理{printf("s.score[%d]:",i);scanf("%f",&s.score[i]);}printf("/*******
*******************************************/\n");printf("No:%ld\nName:%s\n",s.num,s.name);printf("Birthday:%d-%d-%d\n",s.birthday.ye
ar,s.birthday.month,s.birthday.day);for(i=0;i<5;i++){sum=sum+s.score[i];printf("Score%d:%-6.1f",i,s.score[i]);}printf("\nsum=%f
\n",sum);}第9章用户可建立的数据类型——复杂数据的表示与处理运行结果:第9章用户可建立的数据类型——复杂数据的表示与处理分析:在程序中定义两个结构体类型,学生结构中嵌套了日期结构,形成了嵌套结构。定义了结构体变量s来表示具体学生的结构数据。从程序及其运行结果可以看出
,结构体成员的输入/输出只能按基本类型数据元素来进行。例如,输入成员数组元素采用语句“scanf("%f",&s.score[i]);”,输出成员数组元素采用语句“printf("Score%d:%-6.1f
",i,s.score[i]);”。第9章用户可建立的数据类型——复杂数据的表示与处理9.1.4结构体数组批量结构体类型数据如何表示与处理?在实际应用中,经常遇到结构体类型的批量数据,如一个班级的学生信息。一个学生的基本信息是一个结构体类型数据,一个班级的学生基本信息就是一个结构体
数组。C语言允许定义结构体数组。构体数组是复合型构造数据类型,即结构体数组中所有元素是同一类型的结构体数据对象,一个元素是一个结构体数据对象。所以,结构体数组的定义、初始化和元素引用方法都是数组和结构体中方法的类推。第9章用户可建立的数据类型—
—复杂数据的表示与处理因为结构体数组元素是用户自定义的结构体类型,所以定义结构体数组应先定义元素的结构体类型,然后再按已定义的结构体类型定义数组。其定义方式与结构体变量的定义方式相仿。只要在结构体变量定义中的变量名位置写上数组定义符号即可。结
构体数组定义也有与结构体变量定义对应的3种方式。若已定义了结构体类型(具有结构体类型名),则一维结构体数组定义的一般形式为struct结构体类型名数组名[数组长度];其中,“struct结构体类型名”是已经定义过的结构体类型,其他和数组定义一样。另外两种定义方式,在后面的例子
中说明。同样也可定义二维结构体数组。二维结构体数组不太常用,不再细述。第9章用户可建立的数据类型——复杂数据的表示与处理结构体数组的初始化是先按元素顺序,再按元素的结构体成员顺序与类型来提供初始数据。所以就形成了按元素顺序,依次对结构体成员初始化的过程。对结构体数组元素
的引用也是先引用数组元素(结构体对象),再引用该元素中的结构体成员。下面通过一个实例来说明结构体数组的定义、初始化和引用的方法。第9章用户可建立的数据类型——复杂数据的表示与处理例9.2构造一个班一门课程成绩表的数据结构,初始化成绩表信息,查找出不及格学生,并输出该学生的全部信息。成绩表信息包括学
号、姓名、课程、成绩。编程思路:学生基本信息包含不同类型数据,应是一个结构体类型。一个班成绩表应是结构体数组。所以,采用结构体数组进行处理。为简化数据,说明处理方法,程序中只对5个学生信息进行处理。第9章用户可建立的数据类型——复杂数据的表示与处理#include<stdi
o.h>structstudent{longnum;charname[10];charsex;floatscore;}st[5]={{2010301,"zhaoyi",'m',80},{2010302,"qi
aner",'w',50},{2010303,"sunsan",'m',90},{2010304,"lisi",'w',90},{2010305,"wangwu",'m',40}};voidmain(){inti;floatsum=0;第9章用户可建立的数据类型——复杂数
据的表示与处理for(i=0;i<5;i++){sum=sum+st[i].score;if(st[i].score<60){printf("\nNo.%ld\n",st[i].num);printf("name:%s\n",s
t[i].name);printf("sex:%c\n",st[i].sex);printf("score:%f\n",st[i].score);}}printf("\ntotal:%f\n",sum);}第9章用户可建立的数据类型——复杂数据的表示与处理运行结果:第9章用户可建立的数据类型—
—复杂数据的表示与处理分析:(1)在程序开头定义了一个结构体类型,同时定义了结构体数组st[5],又对数组进行了初始化。内层一个花括号对应一个数组元素,花括号内的数据对应一个结构体成员的数据。可以看出,数据类型与所定义的成员类型一一对应。如果去掉
结构体类型名“student”,或者把结构体数组定义放在主函数中,用“structstudentst[5];”定义,程序都能正确运行。请读者自行验证。第9章用户可建立的数据类型——复杂数据的表示与处理
(2)在程序中求总分和输出不及格学生的信息中都采用了“数组名[i].成员名”的引用形式,表示引用数组第i个元素中指定的成员数据。如“st[2].score”是引用结构体数组第2个元素的结构体成员score的值(即对应数组中
的第2个学生的成绩)。从上例可以看出,只要掌握结构体数组复合层次关系,类推数组元素的引用到结构体成员的引用方法,对结构体数组的引用就不难理解。最终都类推到对基本变量的引用上。第9章用户可建立的数据类型——复杂数据的表示与处理9.1.5结构体指针何
谓结构体指针?如何通过结构体指针引用其数据?定义了结构体类型与结构体变量后,系统给结构体数据分配一个存储空间,按照成员顺序连续存储,按成员类型分别占据不同字节的存储长度,每个成员都有确定的存储地址,结构体数据对象的首地址就是结构体的指针。对结构体数据也有两种访问方
式:直接访问和间接访问。前面讲的“结构体变量名·成员名”访问方式就是直接访问,也可以通过指向结构类型的指针变量,来间接访问结构体数据。第9章用户可建立的数据类型——复杂数据的表示与处理结构体数组存储结构也同样保持结
构的复合关系,先按元素顺序连续存储,再按成员顺序和类型分配存储空间。每一个结构体元素及其成员都有确定的存储地址。对结构体数组数据也有两种访问方式。“数组名[下标]·成员名”是直接访问。同样,也可以通过指向结构体数组的指针变量来间接访问。掌握
了指针及指针变量的实质意义,通过指针变量来访问结构体及结构体数组就不难理解了。指向结构体对象的指针变量可指向结构体数据,也可指向结构体数组中的元素。第9章用户可建立的数据类型——复杂数据的表示与处理指向结构体的指针变量定义、赋初值
及通过指针变量引用数据的方法同普通指针变量相仿。只是要用自定义的结构体类型来定义指针变量,取结构体类型变量地址赋给指针变量,即可建立指向。例如:structstudentst;//定义结构体变量str
uctstudent*p;//定义指向结构体指针变量p=&st;//使p指向结构体变量st第9章用户可建立的数据类型——复杂数据的表示与处理通过指针变量对结构体数据的引用有两种方式:方式一:(*指针变量名)·成员名例如:(*p)•name;方式二:指针变量名->成员名例如:p->name;这
两种方式是等价的,可以相互取代。注意:指针变量名两侧的括号是不能缺省的。第9章用户可建立的数据类型——复杂数据的表示与处理1.通过结构体指针变量来引用结构体成员值或结构体数组中的成员值下面通过两个例子来说明通过指针变量来引用结构体数据和结构体数组元素。例9.3通过指向结构体变量的指针变量输出
结构体变量中成员的信息。编程思路:为了便于对比,仍以学生信息表数据为例。第9章用户可建立的数据类型——复杂数据的表示与处理#include<stdio.h>voidmain(){structstudent{longnum;charname[10];charsex;floats
core;}st={2010301,"zhaoyi",'M',80};structstudent*p;p=&st;printf("No.:%ld\nname:%s\nsex:%2c\nscor:%5.1f\n",st.num,st.name,st.sex,st.score);printf(
"\nNo.:%ld\nname:%s\nsex:%2c\nscor:%5.1f\n",(*p).num,(*p).name,(*p).sex,(*p).score);}第9章用户可建立的数据类型——复杂数据的表示与处理运行结果:第9章用户可建立的数据类型——复杂数据的表示与处理分析:在主函数中
定义学生信息结构体类型的同时定义了结构体变量st,并进行了初始化。接着定义了指向结构体类型的指针变量p,&st赋给p,使其指向结构体变量st。两个printf函数调用中,分别采用结构体变量名引用法和指针变量引用法,输出结果完全一样,但意义有所不同,结构体变量名表示结构体数据的地址是固定的,指针
变量的指向是可以变化的。第9章用户可建立的数据类型——复杂数据的表示与处理例9.4通过指向结构体数组的指针变量实现例9.2所要求的功能。voidmain(){structstudent{longnum;charname[10];charsex;floatscore;}st[5]={{201030
1,"zhaoyi",'M',80},{2010302,"qianer",'W',50},{2010303,"sunsan",'M',90},{2010304,"lisi",'W',90},{2010305,"wangwu",'M',40}};structstud
ent*ps;floatsum=0;第9章用户可建立的数据类型——复杂数据的表示与处理for(ps=st;ps<st+5;ps++){sum=sum+ps->score;if((*ps).score<60){
printf("\nNo.:%ld\n",ps->num);printf("name:%s\n",ps->name);printf("sex:%c\n",ps->sex);printf("score:%5.1f\n",ps->score);}}printf("\
ntotal:%f\n",sum);}第9章用户可建立的数据类型——复杂数据的表示与处理分析:程序中定义了指向结构体类型的指针变量ps,把数组名表示的数组首地址赋给ps。在for循环中,“ps=st”使ps指向数组首元素,“ps++”是数组逻辑指针的调整,即使ps指向下一个元素(结构体成
员),“ps<st+5”中的st+5仍是一个逻辑指针,表示ps指向最末一个元素后结束,最末一个元素的指针是st+4。第9章用户可建立的数据类型——复杂数据的表示与处理2.用结构体变量和结构体变量的指针作函数参数从前述已经知道,变量作函数参数,实参向形参单向传递变量的值;指针作函数参数
,实参向形参传递地址,使实参和形参共同指向一个存储单元或存储区,使主调函数和被调函数共享存储单元或存储区中的数据。同样,结构体变量作函数参数,实参向形参传递结构体变量中的成员值,即传递的是不同类型的多个数据;结构体变
量的指针作函数的参数,实参向形参传递结构体数据对象的地址,使主调函数和被调函数能共享结构体存储空间的成员数据,即能实现结构体成员数据的双向传递。下面通过实例来说明,请认真理解。第9章用户可建立的数据类型——复杂数据的
表示与处理例9.5设一个班有3门课程的成绩表,学生学号、姓名已存入系统,从键盘上录入学生3门课成绩,求每个学生的平均成绩,并将平均成绩最高的学生信息输出。编程思路:学生成绩表属于结构体数组结构。从功能上可
由3个函数来实现,显示学生学号、姓名,录入3门课成绩,同时求平均成绩;找出最高平均成绩;输出平均成绩最高的学生信息。第9章用户可建立的数据类型——复杂数据的表示与处理#include<stdio.h>#
defineN3structstudent{longnum;charname[20];floatscore[N];floataver;}st[N]={{20100301,"zhaoyi"},{20100302,
"qianer"},{20100303,"lisan"}};intmain()第9章用户可建立的数据类型——复杂数据的表示与处理{voidinput(structstudentst[]);//函数声明s
tructstudentmax(structstudentst[]);//函数声明voidprint(structstudentstu);//函数声明structstudent*p=st;//定义指针变量,指向结构体数组stinput(p);//调用录入成绩并求平均成绩函数print(ma
x(p));//调用输出学生信息函数(函数调用为参数)return0;}第9章用户可建立的数据类型——复杂数据的表示与处理voidinput(structstudentst[])//定义录入成绩并求平均分函数,结构体数组作
参数{inti,j;floatsum;for(i=0;i<N;i++)//循环实现每个学生学号、姓名,录入成绩{sum=0;printf("%ld",st[i].num);printf("%s\n",st[i].name);printf("inputThreesco
re:");for(j=0;j<3;j++)//循环录入3门课分数{scanf("%f",&st[i].score[j]);sum=sum+st[i].score[j];//求3门课总分}st[i].aver
=sum/N;//求平均分}}第9章用户可建立的数据类型——复杂数据的表示与处理structstudentmax(structstudentst[])//定义找最高平均分函数,结构体数组作参数{inti,m=0;for(i=0;i<N;i++)if
(st[i].aver>st[m].aver)m=i;returnst[m];}voidprint(structstudentstu)//定义输出学生信息函数,结构体变量作参数{printf("\nTheexcellentstudentis:\n");printf("No.:%ld;\nname
:%s\n",stu.num,stu.name);printf("Threscore:%5.1f,%5.1f,%5.1f\n",stu.score[0],stu.score[1],stu.score[2]);printf("average:%6.2f\n
",stu.aver);}第9章用户可建立的数据类型——复杂数据的表示与处理运行结果:第9章用户可建立的数据类型——复杂数据的表示与处理分析:(1)定义学生成绩结构体类型,同时定义结构体数组,只给学号、姓名成员赋初值;(2)定义成绩录入并求平均分函数in
put,结构体数组名作参数,系统把数组名看作指针变量,接收实参传递的指针。屏幕上显示学号、姓名,只输入3门课成绩。外循环控制录入第i个学生成绩,内循环控制录入第j门课成绩。使用了结构体数组元素中的成员元素的引用“st
[i].score[j]”。(3)定义找最高平均分函数,结构体数组名作形参。在循环中只比较数组元素的平均分成员项“st[i].aver>st[m].aver”。第9章用户可建立的数据类型——复杂数据的表示与处理(4)定义输出学生信息函数,结
构体变量作形参,接收实参传递的结构体变量值(全部成员数据)。(5)函数调用,“input(p);”把指针变量p的值(结构体数组首地址)传递给形参st,使p和st都指向结构体数组,函数中录入的成绩就存入结构体数组的成绩数组中,所求平均分存入平均分成员项中。因
为结构体数组属于全局数据对象,所在函数中的操作结果,可供其他函数使用。(6)函数调用,“print(max(p));”先调用“max(p)”,把结构体数组首地址传递给形参,在函数中使用结构体数组中平均分成员数据进行比较,返回最高平均分结构体元素st[m],再产生“print(s
t[m]);”调用,在函数中输出最高平均分学生的全部信息。第9章用户可建立的数据类型——复杂数据的表示与处理9.2共用体9.2.1共用体类型与共用体变量的定义共用体是用户自定义的一种数据存储结构类型。必须先定义类型,再定义变量,通过变量来引用共用
体中的成员。共用体定义的一般形式为union共用体类型名{类型成员名1;类型成员名2;„类型成员名n;}共用体变量名表;第9章用户可建立的数据类型——复杂数据的表示与处理其中,union是共用体类型定义关键字
;共用体类型名是用户自定义的类型名称;花括号中可以是任一类型的数据对象,包括自定义类型;共用体变量名表是用户自定义的共用体类型变量,如果定义多个变量,变量之间要用逗号分隔。共用体定义同结构体相仿,也有3种定义方式。在上述定义中可以不要“共用体类
型名”,也可以在定义共用体类型之后,利用已定义的共用体类型来定义变量。其一般形式为union共用体类型名共用体变量名表;定义了共用体类型与变量后,编译系统按成员中占据存储字节数最多的成员分配一个存储单元或空间。
第9章用户可建立的数据类型——复杂数据的表示与处理系统给i、ch、f按实型数据分配一个存储单元,通过变量a可引用3种数据之一。其存储结构如图9.1所示。为说明问题,假定整型数占2个字节,实型数占4个字节。图9.1共用体存储结构示意图第9章用户可建立的数据类型—
—复杂数据的表示与处理9.2.2共用体变量引用同结构体数据引用相仿,共用体变量只能引用其中的成员,也有两种引用形式。形式一:共用体变量名·成员名形式二:共用体指针变量名->成员名因为共用体成员通过覆盖方式共享一个存储单元或空间,一
个变量的瞬时值只能是一个类型的成员值,所以对共用体赋值及引用,一个时刻只能对一个成员进行操作。这与结构体变量是截然不同的。第9章用户可建立的数据类型——复杂数据的表示与处理关于共用体变量引用的几点说明:(1)共用体变量初始化与赋值。可以对共用体变量初始化,在初
始化表中只能有任一成员类型的常量,不能期望同时给各个成员提供初始数据。例如:uniondata{inti;charch;floatf;}a={230};第9章用户可建立的数据类型——复杂数据的表示与处理实际上是向共用体变量存入一个整型数。如初始化表为{2
30,'a',3.6}则是错误的。可以在程序中给共用体变量的成员赋值,但不能给共用体变量赋值。例如:a.f=3.6;a.ch='a';a.i=230;都是正确的。但如果有a=3.6则是不正确的。如果有多次赋值,共用体变量中只是最后一次所赋的值,即后
面的赋值覆盖前面的赋值。如上面的赋值语句被执行,则引用3个成员的值都是230。第9章用户可建立的数据类型——复杂数据的表示与处理(2)共用体变量的地址和成员的地址是同一地址,即有&a==&a.i==&a.c
h==&a.f,因为3个成员共享一个存储单元。下面通过一个例子来说明共用体数据的使用。例9.6录入表9.1中的数据,并输出。表9.1数据信息编号(num)姓名(name)性别(sex)年龄(age)身份(status)职务(position)班级(company)1001LimingM40p
rof20100301MahongW20301第9章用户可建立的数据类型——复杂数据的表示与处理编程思路:从表中可以看出,教师和学生信息前四项都是相同的,只有最后一项不同。如果在一个实际应用系统中把学生和教师信息以单独表的结构来存储、处理,不但会重复占据存储空间,也给程序设计带来一定的麻烦。如果把
最后一项作共用体数据对象,将会避免上述问题。为说明方法,只编写一位教师和学生的信息处理程序。第9章用户可建立的数据类型——复杂数据的表示与处理#include<stdio.h>structpeople//定义结构体{longnum;charn
ame[20];charsex;intage;charstatus;union//定义共用体,作结构体成员第9章用户可建立的数据类型——复杂数据的表示与处理{intclass;charposition[10];}category;}person[2];vo
idmain(){inti;printf("inputthedataofperson:\n");for(i=0;i<2;i++)第9章用户可建立的数据类型——复杂数据的表示与处理{printf("num:");
scanf("%d",&person[i].num);printf("name:");scanf("%s",&person[i].name);getchar();printf("sex:MorW");s
canf("%c",&person[i].sex);printf("age:");scanf("%d",&person[i].age);getchar();printf("status:'s'or't'");scanf("%c",&person[i].s
tatus);if(person[i].status=='s')第9章用户可建立的数据类型——复杂数据的表示与处理{printf("class:");scanf("%d",&person[i].category.class);}elseif(person[i].status=='t'
){printf("position:");scanf("%s",&person[i].category.position);}elseprintf("inputerror!");printf("\n");}printf("\noutputthe
dataofperson:\n");printf("No.namesexagestatusclass/position\n");for(i=0;i<2;i++)第9章用户可建立的数据类型——复杂数据的表示与处理{printf("%-10d",person[i].num);pr
intf("%-11s",person[i].name);printf("%-4c",person[i].sex);printf("%-6d",person[i].age);printf("%-10c",perso
n[i].status);if(person[i].status=='s')printf("%-10d",person[i].category.class);elseprintf("%-10s",person[i].category.positio
n);printf("\n");}}第9章用户可建立的数据类型——复杂数据的表示与处理运行结果:第9章用户可建立的数据类型——复杂数据的表示与处理分析:程序中定义了全局结构体数组person[2],存储两个人的信息。在结构体类型定义中嵌套定义了一个共用体变量category,其中有两个
成员,company和charposition[10],身份是学生,则存班级信息(整型数据);身份是教师,则存职称信息(字符数组)。使用共用体变量,使两种人员信息统一在一个数据结构中。人员信息输出中,相同信息项作相同处理,只是对不同信息项作
选择处理,简化了程序设计,也提高了程序效率。第9章用户可建立的数据类型——复杂数据的表示与处理9.3枚举类型一些事物属性只能列举,不具有数值关系,这些数据对象怎样表示与处理?现实中存在一些可列举的数据对象,如一周有星期一到星期日,颜色有
红、橙、黄、绿、青、蓝、紫,等等。这种数据对象只可列举,不具有数值关系,似乎难以在计算机中处理。C语言允许将这类数据定义为枚举类型,能方便地进行处理。枚举类型与枚举变量的定义也同结构体相仿。定义的一般形式为第9章用户可建立的数据类型——复杂
数据的表示与处理enum枚举类型名{枚举元素列表}枚举变量列表;其中,enum为定义枚举类型的关键字;枚举类型名是用户自定义的表示所定义枚举类型的名称;“枚举元素列表”是用逗号分隔的列举的元素名称序列;枚举变量列
表是定义枚举类型的同时定义的变量名。一个枚举类型可定义多个变量,变量间用逗号分隔,就是枚举变量列表。枚举类型与枚举变量定义也可有3种形式。在上面的定义中可以省略“枚举类型名”而直接定义枚举变量。也可以先定义
枚举类型,然后用所定义的枚举类型来定义枚举变量。其定义的一般形式为enum枚举类型名枚举变量列表第9章用户可建立的数据类型——复杂数据的表示与处理关于枚举数据的几点说明:(1)枚举元素虽以标号列出,但C编译系统按常量处理
,故称枚举常量。在程序中不能给枚举元素赋值,即枚举元素相当于一个符号常量。(2)C编译系统对枚举元素按定义的顺序依次赋值0,1,2,3,4,5,…。在上面的定义中,Sunday的值为0,Monday的值为1,…
,Saturday的值为6。也可在定义时,给枚举元素指定常量序列值。(3)枚举变量的取值范围是列举元素值的范围。如Sunday只可能取0~7之间的一个整数。(4)由于枚举型变量的值是整数,因此C99标准中也把枚举型作为整型
数据,用整型变量来表示枚举型元素值。第9章用户可建立的数据类型——复杂数据的表示与处理下面通过一个例子来说明枚举数据的应用。例9.7一个盒子中有红、黄、蓝3种颜色的球若干,每次从盒子中先后取出3个球,编程求解取不同颜色球的排列数,并输出每种颜
色排列。编程思路:定义3种颜色的枚举类型,再定义3个枚举类型或整型变量i、j、k,分别表示3个球的颜色值,然后用枚举算法求取出3个球的颜色排列数。枚举算法:当取出的两个球颜色不同(i≠j)时,取第3个球。如果第3个球与前
两个球颜色都不同(k≠i且k≠j),则是一次有效排列取法,计数一次。如此,i、j、k依次取3种颜色值之一,进行判断,可得到求解结果。显然应该用三重循环来实现。第9章用户可建立的数据类型——复杂数据的表示与处
理#include<stdio.h>voidmain(){enumColor{red,yellow,blue};//定义3种颜色的枚举类型inti,j,k,pri;//定义整型变量,表示枚举类型值intn,loop;n=0;for(i=re
d;i<=blue;i++)//使i的值从red到bluefor(j=red;j<=blue;j++)if(i!=j)//使j的值从red到blue{for(k=red;k<=blue;k++)//使k的值从red到blueif((k!=i)&&(k!=j))//3种不同颜色判断{第9
章用户可建立的数据类型——复杂数据的表示与处理n=n+1;//计数printf("%-4d",n);for(loop=1;loop<=3;loop++)//将当前排列的3种颜色值转换{//颜色字符输出switch(loop){case1:pri=i
;break;case2:pri=j;break;case3:pri=k;break;default:break;}switch(pri){第9章用户可建立的数据类型——复杂数据的表示与处理casered:printf("%-10s","red");break;caseyel
low:printf("%-10s","yellow");break;caseblue:printf("%-10s","blue");break;default:break;}}printf("\n");}}printf("\ntotal:%5d\n",n);}第9章用户
可建立的数据类型——复杂数据的表示与处理运行结果:分析:(1)定义了3种颜色的枚举类型后,编译时,3种颜色标号依次具有值0、1、2。(2)定义i、j、k、pri表示颜色取值变量,等价于枚举变量。第9章用户可建立的数据类型——复杂数据的表示与处理(3)三重循
环实现3次取球的颜色排列。第3层内循环的if语句要执行27次,实现3次取球的颜色排列判断。当判断出3个球的颜色不同时,则计数变量n+1,将颜色值转换成颜色字符输出。(4)将颜色值转换成颜色字符输出,由if语句中嵌套的for循环来实现。当判断3个球颜色不同时,由switch(loop)分
别将i、j、k当前值赋给pri,再由switch(pri)输出颜色值对应的颜色字符。(5)使用枚举类型,使枚举元素标号具有整型值,可以很方便地进行比较判断和相应的运算。第9章用户可建立的数据类型——复杂数据的表
示与处理(6)只要在枚举类型中添加颜色元素,再于循环中更改最后一个颜色的取值,即可实现更多种颜色的取球模型求解。取球模型代表了随机抽样一类应用问题。第9章用户可建立的数据类型——复杂数据的表示与处理9.4用户自定义数据类型名称1.用新类型名代
替原有类型名其使用的一般形式为typedef已有类型标识符新类型名;其作用是用“新类型名”代替原有类型标识符,即为原有的一个数据类型重新命名,而不是定义一种新的数据类型。2.用一个简单类型名代替复杂的类型诸如
数组类型、结构体类型、共用体类型、枚举类型等,看起来比较复杂,可用typedef定义一个简单的类型名代替复杂的类型。第9章用户可建立的数据类型——复杂数据的表示与处理(1)用一个新类型名代表数组类型:typedefintNum[100];//定义Num为包含100个元素的
整型数组类型名Numa;//与inta[100];等效(2)用一个新类型名代表指针类型:typedefchar*String;//定义String为字符指针类型Stringp,s[10]//与char*p,*s[10];等效(3)用一个新类型名
代表指向函数的指针类型:typedefint(*Pointer)();//定义Pointer为指向返回值为整型的函数的指针类型Pointerp1,p2;//与int(*p1)(),(*p1)();等效第9章用户可建立的数据类型——复杂数据的表示与处理(4)用
一个新类型名代表结构体类型:typedefstruct{intyear;intmonth;intday;}Data;定义了新类型名Data代表上面的一个结构体类型。可以用Data定义结构体变量。如:Databirthday;//定义了结构体类型变量birthday第9
章用户可建立的数据类型——复杂数据的表示与处理9.5用结构体和指针处理链表9.5.1链表简介链表是动态地进行存储分配的一种数据结构,特别适合规模不确定的复杂数据结构的批量数据表示与处理问题。例如,在一个学生成绩管理系统中,需要处理多个班级的学生数据,每个班学
生数是不固定的。采用数组可以表示成绩表数据,但在定义数组长度时就会产生困惑。按人数少的班级定义数组长度,人数多的班级数据不够用,按人数多的班级定义数组长度,则必然造成存储空间的浪费。采用链表来表示学生成绩表数据
,可完全解除这种困惑。第9章用户可建立的数据类型——复杂数据的表示与处理链表是把一个学生的信息看作一个数据节点,成绩表数据在存储器中不连续存储,通过一个指针把一个班学生数据连接起来,动态地分配内存,即可根据学生数来开辟内存空间。链表也有多种结构,一种简单的单向链表结构如
图9.2所示。图9.2一种简单的单向链表结构第9章用户可建立的数据类型——复杂数据的表示与处理链表中,与一个节点之前连接的节点称为该节点的前驱节点,与一个节点之后连接的节点称为该节点的后继节点。链表的中间节点包含两个域:一是数据域,存放学生实际数据;二是地址域,存放后继节点的地址。每一个链
表都有一个头节点,只有地址域,存放指向链表首节点的地址。每一个链表也有一个尾节点,包含数据域,但地址域为空(NULL),没有后继节点。每一个节点的地址都是由系统动态分配的。第9章用户可建立的数据类型——复杂数据的表示与处理可以看到,表中的元素节点由地址连接起来。访问表中节点数据,首先要
提供头指针,由头节点指针连接表首元素节点,再由此节点连接下一元素节点,直到表尾节点。这样的链接方式,如同一个链条,一环扣一环,中间是不能断开的,所以称为链表。链表中节点数据对象是一个结构体类型。学生成绩表链表节点的数据结
构可定义如下:structnode{intnum;floatscore;structnode*next;//指向下一节点的指针};第9章用户可建立的数据类型——复杂数据的表示与处理9.5.2建立静态链表例9.8建立由4个学生信息节点组成的链表,并输出各节点中的数据
。编程思路:定义节点数据对象为结构体类型,依照连接关系设置每个节点的指针成员,就可形成链表。#include<stdio.h>structnode//定义节点为结构体{longnum;floatscore;structnode*
next;//定义节点指针第9章用户可建立的数据类型——复杂数据的表示与处理};voidmain(){structnodest1,st2,st3,st4,*head,*p;st1.num=20100301;//设置节点数据st1.score=91;st2
.num=20100302;st2.score=80;st3.num=20100303;st3.score=75;st4.num=20100304;st4.score=50;head=&st1;//设置头指针,使其指向首节点st1.next=&st2;//设置第1节点指针,使其
指向第2节点第9章用户可建立的数据类型——复杂数据的表示与处理st2.next=&st3;//设置第2节点指针,使其指向第3节点st3.next=&st4;//设置第3节点指针,使其指向第4节点st4.ne
xt=NULL;//设置尾节点为空p=head;//使p指向头节点do{printf("%ld%5.1f\n",p->num,p->score);p=p->next;//使p指向下一节点}while(p!=NULL);}第9章用户可建立的数据类型——复杂数据的表示与处理运
行结果:分析:建立链表要经历3个步骤:①根据节点数据定义节点结构体,指针成员是不可缺少的;②设置节点数据,只需将数据赋给结构体对应成员;③建立连接关系,只需按节点顺序关系,取结构体变量地址赋值即可。链表节点数据输出,先使指针变量p指向头节点,输出头节点指针所
指向首节点数据,将本节点指针成员的值赋给p,即指向下一节点,一直到p为NULL。第9章用户可建立的数据类型——复杂数据的表示与处理9.5.3建立动态链表建立动态链表需经过以下步骤:(1)使用动态分配函数malloc或calloc申请节点空间,得到节点地址,第一次申请节点为head节点
,地址赋给head。(2)从第1节点开始,申请节点得到地址,录入数据存入节点对应成员中,将节点地址赋给前一节点指针成员。(3)重复第(2)步操作,直到数据录入结束。置最后一个节点的成员指针为NULL。为了实施上述步骤
,需定义两个指针变量p1、p2,p1指向当前节点,p2指向当前节点的前驱节点。当前节点输入的数据,存放到p1所指向节点的成员中,将p1的值赋给p2,如此交替可建立动态链表。第9章用户可建立的数据类型——复杂数据的表示与处理例9.9仍以4个学生成绩为例来说明动态链表的建立。#
include<stdio.h>#include<malloc.h>#defineLENsizeof(structnode)//测定结构体所占字节数,用LEN表示structnode{longnum;floatscore;structnode*next;};int
n;structnode*creat(void)//定义动态建立链表函数,返回头指针第9章用户可建立的数据类型——复杂数据的表示与处理{structnode*head;//定义3个结构体类型指针structnode*p1,*p2;n=0;p1=(structnode*)mall
oc(LEN);//为节点申请内存空间,将返回地址强制转换p2=p1;printf("inputNo.1data:num,score->");scanf("%ld,%f",&p1->num,&p1->score);//输入第1节点数据head=
NULL;while(p1->num!=0)//输入学号为0,结束循环第9章用户可建立的数据类型——复杂数据的表示与处理{n=n+1;//记录节点序号if(n==1)head=p1;//申请的第1节点,作头节点elsep2->next=p1;//使前驱节点连接到本节点上p2=p1;
//本节点前驱节点p1=(structnode*)(malloc(LEN));//申请节点空间printf("inputNo.%ddata:num,score->",n+1);scanf("%ld,%f",&p1->num,&p1->score);//输入当前节点数据}p2->nex
t=NULL;//置节点指针成员为空return(head);//函数返回链表的头节点}第9章用户可建立的数据类型——复杂数据的表示与处理voidmain(){structnode*p;p=creat();do{printf(
"\nnum:%ld\nscore:%5.1f\n",p->num,p->score);p=p->next;}while(p!=NULL);}第9章用户可建立的数据类型——复杂数据的表示与处理运行结果:第9章用户可建立的数据类
型——复杂数据的表示与处理分析:定义creat函数实现动态链表的建立,返回值是链表头指针。定义了3个结构体类型指针,head用于指向链表头节点,p1用于指向当前节点,p2用于指向当前节点的前驱节点,在循环中交替变
化,从而实现了指针的移动。“p1=(structnode*)malloc(LEN);”是按测定的结构体所占内存字节数申请节点空间,函数返回值是存储空间首地址,为匹配结构体类型指针p1,进行了强制类型转换。链表还有诸
如插入、删除等基本操作,请读者在本章基础上自行设计程序。第9章用户可建立的数据类型——复杂数据的表示与处理实训任务十七熟悉结构体、共用体数据类型的表示与使用实训项目1分析问题,从每小题的4个备选项中选择一个正确项。(1)
有以下结构体说明和变量的定义,如图9.3所示,指针p指向变量a,指针q指向变量b,则不能把节点b连接到节点a之后的语句是()。structnode{chardata;structnode*next;}a,b,*p=&a,*q=&b;第9章用户
可建立的数据类型——复杂数据的表示与处理A.a.next=q;B.p.next=&b;C.p->next=&b;D.(*p).next=q;图9.3结构体变量说明第9章用户可建立的数据类型——复杂数据的表示与处理(2)下列程序中,结构体变量a所占内存字节数是()。unionU{charst[4];
inti;longl;};structA{intc;unionUu;}a;A.4B.5C第9章用户可建立的数据类型——复杂数据的表示与处理(3)以下对结构体类型变量的定义中,不正确的是()。A.typedefstructaaB.#defineAAs
tructaa{intn;floatm;}AA;AA{intn;floatm;}td1;AAtd1;C.struct{intn;floatm;}aa;D.struct{intn;floatm;}td1;stuctaatd
1;第9章用户可建立的数据类型——复杂数据的表示与处理实训项目2分析程序功能及执行结果,并上机验证。程序1:structstudent//建立学生结构体并赋值{intnumber;charname[10];charsex;floatscore;}stu[
5]={{1,"Zhangsan",'M',40},{2,"Lisi",'M',60.5},第9章用户可建立的数据类型——复杂数据的表示与处理{3,"Wangwu",'G',76},{4,"Zhaoliu",'M',21},{5,"Maqi",'M',86},};voidmai
n(){inti,count=0;floata,sum=0;for(i=0;i<5;i++)第9章用户可建立的数据类型——复杂数据的表示与处理{sum+=stu[i].score;if(stu[i].score>60)coun
t=count+1;/*计算及格人数*/}printf("s=%f\n",sum);a=sum/5;/*计算平均分*/printf("average=%f\ncount=%d\n",a,count);}第9章用户可建立的数据类型——复杂数据
的表示与处理程序2:#include<stdio.h>structstudent//定义结构体{intnumber;intcomputer,maths,english;ints;};voidp(structstudenta)//定义结构体格式输出函数{prin
tf("number=%d\tcomputer=%d\tmaths=%d\tenglish=%d\n",a.number,a.computer,a.maths,a.english);第9章用户可建立的数据类型——复杂数据的表示与处理}voidm
ain(){structstudentb;//定义结构体变量并赋值b.number=6;b.computer=62;b.maths=79;b.english=90;p(b);//调用结构体格式输出函数}第9章用户可建立的数
据类型——复杂数据的表示与处理实训项目3分析程序,在下划线处填写适当的语句代码,使程序能够正确运行。有5名学生,每个学生的数据信息包括学号、姓名和一门课的成绩。要求按学生的成绩由高到低排序,然后输出学生的信息
以及平均成绩。#include<stdio.h>structstudent//定义结构体{intnum;charname[20];intscore;第9章用户可建立的数据类型——复杂数据的表示与处理}stu[5];//定义结构体数组voi
dmain(){structstudent*pt,*p[5];inti,j,k,sum=0;for(i=0;i<5;i++)//结构体数组变量赋值{scanf("%d%s%d",&stu[i].num,stu[i].name,&stu[i].score);p[i]=&stu[i];sum
=sum+;//求总分}for(i=0;i<5;i++)第9章用户可建立的数据类型——复杂数据的表示与处理{k=i;for(j=i;j<=5;j++)if()k=j;if(k!=i){pt=p[i];p[i]=p[k];p[k]=pt;}//成绩排序}for(i=0;i<5;i++)print
f("%d,%s,%d",);printf("Average=%d\n",);}第9章用户可建立的数据类型——复杂数据的表示与处理实训任务十八学习复杂数据表示处理的编程方法完成以下项目问题的程序设计,并调试运行,实现
功能要求。实训项目1有10名学生,每个学生的信息包括学号、姓名、高等数学成绩、英语成绩,编写程序完成以下功能。(1)从键盘输入数据,将其存放在结构体数组中;(2)输入姓名,在数组中查找是否存在此学生,有此学生则输出此学生的信息,无此同学则输出提
示信息;(3)输入一个成绩,将高于此成绩的学生信息输出;(4)输出不及格学生信息。第9章用户可建立的数据类型——复杂数据的表示与处理实训项目2定义一个表示年、月、日的结构体,输入年、月、日数值存入结构体。计算该日是本年的第几天,输出处理结果。实训项目3创建a、b两个
链表,每个链表中的节点包括学号和成绩,两个链表的学号都是连续且按升序排列的,要求合并两个链表。