结构体、共用体与枚举.ppt
9 9结构体、共用体与枚举结构体、共用体与枚举本章导读本章导读 用用户户定定义义类类型型结结构构体体、共共用用体体和和枚枚举举类类型型,包括它们的定义、变量的说明和应用。包括它们的定义、变量的说明和应用。结结构构体体类类型型:结结构构体体数数组组和和指指针针、结结构构体体变变量量和和指指针针作作为为函函数数参参数数、返返回回结结构构体体类类型型数数据据的的函函数数、动动态态内内存存分分配配、链链表表;类类型型定定义义符符typedef;了了解解结结构构体体、共共用用体体和和枚枚举举类类型型数数据据的的特特点点,熟熟练练掌掌握握结结构构体体类类型型、变变量量、数数组组、指指针针变变量量的的定定义义、初初始始化化和和成成员员的的引引用用方方法法;掌掌握握共共用用体体和和枚枚举举类类型型、变变量量的的定定义义和和引引用用;掌掌握握用用户户自自定定义义类型的定义和使用。类型的定义和使用。9.1结构体结构体【问题】什么是结构体类型?什么是结构体变量?结【问题】什么是结构体类型?什么是结构体变量?结构体类型与数组类型有什么区别和联系?构体类型与数组类型有什么区别和联系?姓名姓名年龄年龄 性别性别身份身份证号证号民族民族住址住址电话电话号码号码(字符数组字符数组)(整型整型)(字符字符)(长整型长整型)(字符字符)(字符数组字符数组)(长整型长整型)9.1.1 结构体类型的定义结构体类型的定义结构体类型的定义形式为:结构体类型的定义形式为:struct 类型类型名名成员项表列成员项表列;例如包含上图中全部类型数据的结构体类型的定义如下:例如包含上图中全部类型数据的结构体类型的定义如下:struct person /*结构体类型名结构体类型名*/char name20;/*以下定义成员项的类型和名字以下定义成员项的类型和名字*/int age;char sex;long num;char nation;char address20;long tel;9.1.2 结构体变量的说明结构体变量的说明结构体变量的说明有三种方法:结构体变量的说明有三种方法:1.用已定义的结构体类型名定义变量。用已定义的结构体类型名定义变量。例如:例如:struct person student,worker;/*定义了两个结构体变量定义了两个结构体变量student和和worker*/用上面的结构体类型还可再定义变量:用上面的结构体类型还可再定义变量:struct person men,women;2.在定义结构体类型的同时定义结构体变量。例如:在定义结构体类型的同时定义结构体变量。例如:struct person char name20;int age;long tel;student,worker;一般的形式为:一般的形式为:struct 类型名类型名 成员项表列成员项表列 变量名表列;变量名表列;这样定义的结构体类型也还可多次使用,如:这样定义的结构体类型也还可多次使用,如:struct person men,women;9.1.2 结构体变量的说明结构体变量的说明3.不定义结构体类型名,直接定义结构体变量。不定义结构体类型名,直接定义结构体变量。一般形式为:一般形式为:struct 成员项表列成员项表列变量名表列;变量名表列;9.1.2 结构体变量的说明结构体变量的说明9.1.3 结构体变量的初始化结构体变量的初始化 在以上结构体变量的三种定义的同时都可以进行初始化在以上结构体变量的三种定义的同时都可以进行初始化赋值,例如:赋值,例如:struct person stud1=Wang Li,18,M,34011,h,12,13 Bejing Road,2098877,stud2=Yu Ping,19,F,34082,h,12,25 Hefei Road,5531678;注意初始化数据应与类型中的各个成员在位置上一一对注意初始化数据应与类型中的各个成员在位置上一一对应。对于嵌套的结构体类型变量,初始化是对各个基本类型应。对于嵌套的结构体类型变量,初始化是对各个基本类型的成员赋初值,例如:的成员赋初值,例如:struct person student=Wang Li,12,5,1974,M,340201,h,12,13 Bejing Road,2098877;9.1.4 结构体变量的引用结构体变量的引用1.引用结构体成员引用结构体成员 在在无无嵌嵌套套的的情情况况下下,引引用用结结构构体体变变量量成成员员的的形形式式为:为:结构体变量名结构体变量名成员名成员名 其中的其中的“.”叫叫“结构体成员运算符结构体成员运算符”,这样引,这样引用的结构体成员相当于一个普通变量用的结构体成员相当于一个普通变量,例如:,例如:student.num /*结构体变量结构体变量student的成员的成员num,相当于一个长整型变量相当于一个长整型变量*/student.name /*结构体变量结构体变量student的成员的成员name,相当于一个字符数组名相当于一个字符数组名*/在在有有嵌嵌套套的的情情况况下下,访访问问的的应应是是结结构构体体的的基基本本成成员员,因因为为只只有有基基本本成成员员直直接接存存放放数数据据,且且数数据据是是基基本本类类型型或或上上面面介介绍绍的的数数组组类类型型,引引用用形形式式为:为:结结构构体体变变量量名名结结构构体体成成员员名名结结构构体体成成员员名名基基本本成成员员名名 即即从从结结构构体体变变量量开开始始,用用成成员员运运算算符符“.”逐逐级级向向下下连连接接嵌嵌套套的的成成员员直直到到基基本本成成员员,不不能能省省略,例如:略,例如:student.birthday.year /*基本成员基本成员year,相当于一个整型变量相当于一个整型变量*/9.1.4 结构体变量的引用结构体变量的引用2.结构体变量的赋值、输入和输出结构体变量的赋值、输入和输出 由于结构体各个成员的类型不同,对结构体变量由于结构体各个成员的类型不同,对结构体变量赋值也只能对其成员进行赋值也只能对其成员进行 结构体变量的输入和输出也都只能对其成员进行结构体变量的输入和输出也都只能对其成员进行 3.同一类型的结构体变量可相互赋值同一类型的结构体变量可相互赋值 同类型的两个结构体变量之间可以整体赋值同类型的两个结构体变量之间可以整体赋值(请比较(请比较数组之间不能整体赋值)数组之间不能整体赋值)stud1=stud2;9.1.4 结构体变量的引用结构体变量的引用【例【例9-19-1】输出结构体数据】输出结构体数据#include main()struct person char name20;struct int month;int day;int year;bd;char sex;long num;st=Wang Li,12,15,1974,M,340201;printf(%s,%d,%d,%d,st.name,st.bd.year,st.bd.month,st.bd.day);printf(%c,%ldn,st.sex,st.num);9.1.5 结构体数组结构体数组1.结构体数组的定义结构体数组的定义 有三种方法。有三种方法。(1)先先定定义义结结构构体体类类型型,用用结结构构体体类类型型名名定定义义结结构构体体数数组,如:组,如:struct stud_typechar name20;long num;int age;char sex;float score;struct stud_type student50;9.1.5 结构体数组结构体数组(2)定义结构体类型名的同时定义结构体数组,如:定义结构体类型名的同时定义结构体数组,如:struct stud_typestudent50;(3)不定义结构体类型名,直接定义结构体数组,如:不定义结构体类型名,直接定义结构体数组,如:structstudent50;2.结构体数组的初始化结构体数组的初始化 结构体数组的一个元素相当于一个结构体变量,结构体数组的一个元素相当于一个结构体变量,结构体数组初始化即顺序对数组元素初始化。结构体数组初始化即顺序对数组元素初始化。如:如:struct stud_type student3=Wang li,80101,18,M,89.5,Zhang Fun,89102,19,M,90.5,Li Ling,89103,20,F,98;9.1.5 结构体数组结构体数组9.1.5 结构体数组结构体数组3.结构体数组的引用。结构体数组的引用。(1)除除初初始始化化外外,对对结结构构体体数数组组赋赋常常数数值值、输输入入和和输输出出、各各种种运运算算均均是是对对结结构构体体数数组组元元素素的的成成员员(相相当当于于普普通通变变量量)进进行行的的。结结构构体体数数组组元元素素的的成员表示为:成员表示为:结构体数组名结构体数组名下标下标.成员名成员名在嵌套的情况下为:在嵌套的情况下为:结构体数组名结构体数组名下标下标结构体成员名结构体成员名结构体结构体成员名成员名成员名成员名(2)结构体数组元素可相互赋值结构体数组元素可相互赋值例如:例如:student1=student2;对对于于结结构构体体数数组组元元素素内内嵌嵌的的结结构构体体类类型型成成员员,情情况况也相同。如:也相同。如:student2.birthday=student1.birthday;(3)其他注意事项也与结构体变量的引用相同,例如:其他注意事项也与结构体变量的引用相同,例如:不允许对结构体数组元素或结构体数组元素内嵌的结不允许对结构体数组元素或结构体数组元素内嵌的结构体类型成员整体赋(常数)值;不允许对结构体数构体类型成员整体赋(常数)值;不允许对结构体数组元素或结构体数组元素内嵌的结构体类型成员整体组元素或结构体数组元素内嵌的结构体类型成员整体进行输入输出等。进行输入输出等。9.1.5 结构体数组结构体数组9.1.5 结构体数组结构体数组在在处处理理结结构构体体问问题题时时经经常常涉涉及及字字符符或或字字符符串串的的输输入入,这时要注意:这时要注意:scanf()函函数数用用%s输输入入字字符符串串遇遇空空格格即即结结束束,因因此此输入带空格的字符串可改用输入带空格的字符串可改用gets函数。函数。在输入字符类型数据时往往得到的是空白符(空在输入字符类型数据时往往得到的是空白符(空格、回车等),甚至运行终止,因此常作相应处理,格、回车等),甚至运行终止,因此常作相应处理,即在适当的地方增加即在适当的地方增加getchar();空输入语句,以消空输入语句,以消除缓冲区中的空白符。除缓冲区中的空白符。【例【例9-2】输入】输入3个学生的信息然后输出。每个学个学生的信息然后输出。每个学生的信息包括学号、姓名和生的信息包括学号、姓名和4门课程的成绩门课程的成绩#include main()struct stu_type long num;char name20;float score4;st3;int i,j;float t;printf(Enter students datas:n);for(i=0;i3;i+)scanf(%ld,&sti.num);getchar();gets(sti.name);【例【例9-2】for(j=0;j4;j+)scanf(%f,&t);sti.scorej=t;printf(No.ttNamettScore1tScore2tScore3tScore4n);for(i=0;i3;i+)printf(%ldt%st,sti.num,sti.name);for(j=0;jnum第二种表示与第一种表示等价,运算符第二种表示与第一种表示等价,运算符“-”与与“.”优先级相同,具有最高的优先级。优先级相同,具有最高的优先级。9.1.6 结构体指针结构体指针【例【例9-39-3】利用结构体指针变量输出结构体数据】利用结构体指针变量输出结构体数据/*EX9-3.C */main()struct stu_typelong num;char name20;float score2;student=20050101,wang,89,77.5,*p;p=&student;printf(%ldt%st%6.1f%6.1fn,p-num,p-name,p-score0,p-score1);2.结构体数组与结构体指针变量结构体数组与结构体指针变量一维数组的数组名代表数组的首地址,一维结构体一维数组的数组名代表数组的首地址,一维结构体数组也一样。可以将一维结构体数组名赋给指向结数组也一样。可以将一维结构体数组名赋给指向结构体变量的指针变量,该指针变量将指向下标为构体变量的指针变量,该指针变量将指向下标为0 0的元素,它可以的元素,它可以在数组元素之间移动。在数组元素之间移动。【例【例9-4】用指向结构体变量的指针变量输】用指向结构体变量的指针变量输出结构体数组出结构体数组/*EX9-4.C */main()struct stu_typelong num;char name20;int age;st3=1001,wang,19,1002,li,18,1003,zhang,20,*p;printf(No.tNametAgen);for(p=st;pnum,p-name,p-age);【例【例9-5】输出上例中全部学生的】输出上例中全部学生的name信息信息/*EX9-5.C */main()struct stu_typelong num;char name20;int age;st3=1001,wang,19,1002,li,18,1003,zhang,20,*p,*q;q=(struct stu_type*)st0.name;for(p=q;pq+3;p+)printf(%st,p);9.1.7 结构体与函数结构体与函数1.结构体变量和结构体变量成员做函数参数结构体变量和结构体变量成员做函数参数(1)结构体变量成员作为函数的实参结构体变量成员作为函数的实参由于结构体变量成员存放基本类型数据,因此这种情况由于结构体变量成员存放基本类型数据,因此这种情况同基本类型有值变量做实参,实现值传递。要注意实参同基本类型有值变量做实参,实现值传递。要注意实参与形参类型的一致。与形参类型的一致。【例【例9-69-6】打印学号为】打印学号为2005010220050102学生的年龄学生的年龄#define N 3void PRINT(int age)printf(Age:%dn,age);main()struct stu_typelong num;char name20;int age;stN=20050101,wang,19,20050102,li,18,20050103,zhao,20;int i;for(i=0;iN;i+)if(sti.num=20050102)PRINT(sti.age);(2)结构体变量作为函数参数结构体变量作为函数参数这种用法的参数形式为:这种用法的参数形式为:形参:结构体变量;形参:结构体变量;实参:有值结构体变量或结构体数组元素。实参:有值结构体变量或结构体数组元素。通通过过实实参参将将相相应应的的结结构构体体类类型型数数据据传传给给对对应应的的形形参参,实现传值调用,不同于数组作参数的传址调用!实现传值调用,不同于数组作参数的传址调用!【注意】在结构体类型数据作为函数参数时,为了【注意】在结构体类型数据作为函数参数时,为了在虚实结合时保持形参与实参类型的一致,应将结构在虚实结合时保持形参与实参类型的一致,应将结构体类型定义成外部的,即在所有函数之前定义结构体体类型定义成外部的,即在所有函数之前定义结构体类型。类型。9.1.7 结构体与函数结构体与函数【例【例9-79-7】打印学号为】打印学号为2005010220050102学生的全部信息学生的全部信息#define N 3struct stu_typelong num;char name20;int age;void PRINT(struct stu_type stu)printf(No.ttNametAgen);printf(%-16ld%st%dn,stu.num,stu.name,stu.age);【例【例9-7】main()struct stu_type stN =20050101,wang,19,20050102,li,18,20050103,zhao,20;int i;for(i=0;iN;i+)if(sti.num=20050102)PRINT(sti);2.结构体指针作为函数参数结构体指针作为函数参数此此用用法法一一般般用用于于结结构构体体数数组组问问题题。与与基基本本类类型型一一维维数组的情况相同,实现传址调用,参数用法如下:数组的情况相同,实现传址调用,参数用法如下:形参:形参:结构体数组或结构体指针变量;结构体数组或结构体指针变量;实参:实参:结构体数组名或取得数组名首地址的结构体结构体数组名或取得数组名首地址的结构体指针变量。指针变量。【例【例9-8】同上例,输出全部学生的信息】同上例,输出全部学生的信息#define N 3struct stu_typelong num;char name20;int age;void PRINT(struct stu_type*p)int i;printf(No.ttNametAgen);for(i=0;inum,(p+i)-name,(p+i)-age);main()struct stu_type stN=20050101,wang,19,20050102,li,18,20050103,zhao,20;PRINT(st);3.返回结构体类型数据的函数返回结构体类型数据的函数 函数返回值可以是结构体类型的值,也可以是函数返回值可以是结构体类型的值,也可以是指向结构体变量(或数组元素)的指针。当函数返指向结构体变量(或数组元素)的指针。当函数返回值是结构体类型的值时,称该函数为结构体类型回值是结构体类型的值时,称该函数为结构体类型函数;当函数返回值是指向结构体类型存储单元的函数;当函数返回值是指向结构体类型存储单元的指针时,称该函数为结构体类型指针函数。指针时,称该函数为结构体类型指针函数。【例【例9-99-9】同【例】同【例9-79-7】,打印学号为】,打印学号为2005010220050102学学生的全部信息,查找用结构体类型函数实现生的全部信息,查找用结构体类型函数实现#define N 3struct stu_typelong num;char name20;int age;struct stu_type fun(struct stu_type st)int i;for(i=0;i,p-data);p=p-next;printf(NULLn);【例【例9-11】建立一个简单的链表并输出】建立一个简单的链表并输出struct nodeint data;struct node*next;main()struct node a,b,c,*head,*p;head=&a;a.data=5;a.next=&b;b.data=10;b.next=&c;2.Turbo C 动态存储分配函数动态存储分配函数Turbo C动动态态存存储储分分配配函函数数有有:malloc、calloc、free、realloc,这些函数的定义均包含在头文件这些函数的定义均包含在头文件stdlib.h中。中。(1)malloc函数函数void*malloc(unsigned int size)调用形式为:调用形式为:(类型类型*)malloc(size)例如:例如:int *pi;float *pf;pi=(int*)malloc(2);pf=(float*)malloc(4);(2)calloc函数函数void*calloc(unsigned n,unsigned size)调用形式为:调用形式为:(类型类型*)calloc(n,size)如:如:char*ps;ps=(char*)calloc(10,sizeof(char);2.Turbo C 动态存储分配函数动态存储分配函数(3)realloc函函 数数 void*realloc(void*ptr,unsigned newsize)调用形式为:调用形式为:(类型类型*)realloc(ptr,newsize)(4)free函数函数 void free(void*)调用形式为:调用形式为:free(p);其其中中指指针针变变量量p必必须须是是由由malloc、calloc、realloc函函数数分分配配存存储储单单元元存存放放首首地地址址的的指指针针变变量量,该该函函数数的的作作用用是是收收回由回由p指向的动态分配的存储单元。该函数无返回值。指向的动态分配的存储单元。该函数无返回值。2.Turbo C 动态存储分配函数动态存储分配函数3.3.动态存储分配链表的基本操作动态存储分配链表的基本操作由包含一个指针域的结点组成的链表为单向链表。由包含一个指针域的结点组成的链表为单向链表。建立并初始化链表建立并初始化链表遍历访问链表(包括查找结点、输出结点等)遍历访问链表(包括查找结点、输出结点等)删除链表中的结点删除链表中的结点在链表中插入结点在链表中插入结点(1)建立单向链表建立单向链表建立单向链表的步骤如下:建立单向链表的步骤如下:建立头结点(或定义头指针变量);建立头结点(或定义头指针变量);读取数据;读取数据;生成新结点;生成新结点;将数据存入结点的数据域中;将数据存入结点的数据域中;将将新新结结点点连连接接到到链链表表中中(将将新新结结点点地地址址赋赋给给上一个结点的指针域)。上一个结点的指针域)。重复步骤重复步骤,直到输入结束。,直到输入结束。3.3.动态存储分配链表的基本操作动态存储分配链表的基本操作【例【例9-159-15】建立带有头结点的单向链表,当输】建立带有头结点的单向链表,当输入入-1-1时结束。时结束。#include struct nodeint data;struct node *next;main()int x;struct node *h,*s,*r;h=(struct node*)malloc(sizeof(struct node);r=h;scanf(%d,&x);while(x!=-1)s=(struct node*)malloc(sizeof(struct node);s-data=x;r-next=s;r=s;scanf(%d,&x);r-next=NULL;(2)输出链表输出链表输出链表即顺序访问链表中各结点的数据域,方输出链表即顺序访问链表中各结点的数据域,方法是:从头结点开始,不断地读取数据和下移指法是:从头结点开始,不断地读取数据和下移指针变量,直到尾结点为止。针变量,直到尾结点为止。【例【例9-16】编写单向链表的输出函数。】编写单向链表的输出函数。void print_slist(struct node *h)struct node *p;p=h-next;if(p=NULL)printf(Linklist is null!n);else printf(head);while(p!=NULL)printf(-%d,p-data);p=p-next;printf(-endn);(3)删除单向链表中的一个结点)删除单向链表中的一个结点删除单向链表中一个结点的方法步骤如下,参见删除单向链表中一个结点的方法步骤如下,参见 找到要删除结点的前驱结点;找到要删除结点的前驱结点;将将要要删删除除结结点点的的后后继继结结点点的的地地址址赋赋给给要要删删除除结结点点的前驱结点的指针域;的前驱结点的指针域;将要删除结点的存储空间释放。将要删除结点的存储空间释放。【例【例9-17】编写函数,在单向链表中删除值为】编写函数,在单向链表中删除值为x的结点的结点/*EX9-17.C */void delete_node(struct node*h,int x)struct node*p,*q;q=h;p=h-next;/*工作指针初始化,工作指针初始化,q在前、在前、p在后指向第一个结点在后指向第一个结点*/if(p!=NULL)/*表非空表非空*/while(p!=NULL)&(p-data!=x)/*未到表尾,查找未到表尾,查找x的位置的位置*/q=p;p=p-next;/*p、q下移,下移,q指向指向p的前趋结点的前趋结点*/if(p-data=x)q-next=p-next;free(p);/*删除值为删除值为x的结点的结点*/(4)在单向链表的某结点前插入一个结点)在单向链表的某结点前插入一个结点在单向链表的某结点前插入一个结点的步骤如下:在单向链表的某结点前插入一个结点的步骤如下:开辟一个新结点并将数据存入该结点的数据域;开辟一个新结点并将数据存入该结点的数据域;找到插入点结点;找到插入点结点;将新结点插入到链表中:将新结点的地址赋给插入点上一将新结点插入到链表中:将新结点的地址赋给插入点上一个结点的指针域,并将插入点的地址存入新结点的指针域个结点的指针域,并将插入点的地址存入新结点的指针域【例【例9-189-18】分分析析:本本例例结结合合了了查查找找和和插插入入两两种种功功能能,可可能能遇遇到三种情况:到三种情况:链链表表非非空空,值值为为x的的结结点点存存在在,则则插插在在值值为为x的的结结点之前;点之前;链表非空链表非空,值为值为x的结点不存在的结点不存在,则插在表尾;则插在表尾;链链表表为为空空,也也相相当当于于值值为为x的的结结点点不不存存在在,则则插插在表尾。在表尾。编写函数,在单向链表中值为编写函数,在单向链表中值为x x的结点前插入值为的结点前插入值为y y的结点,若值为的结点,若值为x x的结点不存在,则插在表尾。的结点不存在,则插在表尾。【例【例9-189-18】函数编写如下:函数编写如下:void insert_node(struct node*h,int x,int y)struct node*s,*p,*q;s=(struct node*)malloc(sizeof(struct node);s-data=y;/*向新结点存入数据向新结点存入数据*/q=h;p=h-next;/*工作指针初始化,工作指针初始化,p指向第一个结点指向第一个结点*/while(p!=NULL)&(p-data!=x)q=p;p=p-next;/*p、q下移,下移,q指向指向p的前趋结点的前趋结点*/q-next=s;s-next=p;9.2 共用体共用体问题问题:什么是共用体类型?什么是共用体变量?共什么是共用体类型?什么是共用体变量?共用体类型与结构体类型有什么区别和联系?用体类型与结构体类型有什么区别和联系?9.2.1 共用体类型的定义共用体类型的定义共共用用体体类类型型的的定定义义与与结结构构体体类类型型的的定定义义类类似似,但但所所用用关关键键字字不不同同,共共用用体体类类型型用用关关键键字字union定定义义,具体形式为:具体形式为:union 类型名类型名成员项表列成员项表列;union exam int a;float b;char c;9.2.2 共用体变量的说明共用体变量的说明与结构体变量的说明类似,也有三种方式:与结构体变量的说明类似,也有三种方式:1先定义共用体类型,再用共用体类型定义共用体变量先定义共用体类型,再用共用体类型定义共用体变量union 类型名类型名成员表列成员表列;union 类型名类型名 变量名表;变量名表;例如用例如用union exam类型定义共用体变量类型定义共用体变量x、y:union exam x,y;2定义共用体类型名的同时定义共用体变量定义共用体类型名的同时定义共用体变量union 类型名类型名成员表列成员表列变量名表;变量名表;union exam int a;float b;char c;x,y;3不定义类型名直接定义共用体变量不定义类型名直接定义共用体变量union 成员表列成员表列 变量名表变量名表;定定义义了了共共用用体体变变量量后后,系系统统为为共共用用体体变变量量开开辟辟一一定定的的存存储储单单元元。由由于于共共用用体体变变量量先先后后存存放放不不同同类类型型的的成成员员,系系统统开开辟辟的的共共用用体体变变量量的的存存储储单单元元的的字字节节数数为为最最长长的的成成员员需需要要的的字字节节数数。例例如如对对上上面面定定义义的的共共用用体体类类型型union exam或或变变量量x,表达式表达式sizeof(union exam)和和sizeof(x)的值均为的值均为4。另外,先后存放各成员的首地址都相同,即共用体变量、另外,先后存放各成员的首地址都相同,即共用体变量、共用体变量的所有成员它们的首地址都相同。共用体变量的所有成员它们的首地址都相同。9.2.3 共用体变量的引用共用体变量的引用1.共用体变量的引用共用体变量的引用 引引用用共共用用体体变变量量的的形形式式以以及及注注意意事事项项均均与与引引用用结结构体变量相似,其要点如下:构体变量相似,其要点如下:(1)一一般般只只能能引引用用共共用用体体变变量量的的成成员员而而不不能能整整体体引引用用共共用用体体变变量量,尽尽管管它它同同时时只只有有一一个个成成员员有有值值。共共用用体体变变量量的的一一个个基基本本类类型型成成员员相相当当于于一一个个普普通通变变量量,可可参参与与该该成成员员所所属属数数据据类类型型的的一一切切运运算算。例例如如对对上上面面定定义的共用体变量义的共用体变量x可以引用的成员有:可以引用的成员有:x.ax.bx.c1.共用体变量的引用共用体变量的引用(2)与与结结构构体体类类似似,同同一一类类型型的的共共用用体体变变量量可可相相互互赋赋值值。例例如如有有赋赋值值语语句句 x.a=3;共共用用体体变变量量x有有值,则可有下面的赋值语句:值,则可有下面的赋值语句:y=x;这样这样y.a的值也为的值也为3。(3)在赋值和输入输出方面也与结构体类似,即在赋值和输入输出方面也与结构体类似,即不允许对共用体变量整体赋(常数)值;共用体不允许对共用体变量整体赋(常数)值;共用体的输入和输出也只能对共用体变量的成员进行,的输入和输出也只能对共用体变量的成员进行,不允许直接对共用体变量进行输入和输出,尽管不允许直接对共用体变量进行输入和输出,尽管它同时只存有一个成员!它同时只存有一个成员!2.共用体的应用共用体的应用(1)变体记录问题变体记录问题【例例9-19】输输入入N个个人人的的信信息息,共共同同的的信信息息有有:姓姓名名、性性别别,另另外外,职职业业(job)为为教教师师(t)则则登登记记其其单单位位(group),职职业业为为学学生生(s)则则登登记记其其班班级级(class),最最后后将将信信息息输输出出。程序如下:程序如下:#define N 2main()struct char name20;char sex;char job;union int class;char group20;category;personN;int i;printf(Enter%d person informations:n,N);for(i=0;iN;i+)gets(personi.name);scanf(%c,&personi.sex);scanf(%c,&personi.job);getchar();【例【例9-19】if(personi.job=s)scanf(%d,&personi.category.class);else if(personi.job=t)scanf(%s,personi.category.group);getchar();printf(NametSextJobtGroup/Classn);for(i=0;iwhite)printf(It is block.);2.枚举变量的引用枚举变量的引用(3)枚举变量还可以进行枚举变量还可以进行+、-等运算。等运算。(4)枚举变量不能通过枚举变量不能通过scanf或或gets函数输入枚举常量,函数输入枚举常量,只能通过赋值取得枚举常量值。但是枚举变量可以通过只能通过赋值取得枚举常量值。但是枚举变量可以通过scanf(%d,&枚举变量枚举变量);输入枚举常量对应的整数值。;输入枚举常量对应的整数值。(5)枚举变量和枚举常量可以用枚举变量和枚举常量可以用printf(“%d”,);输出对输出对应的整数值,若想输出枚举值字符串,则只能间接进行,应的整数值,若想输出枚举值字符串,则只能间接进行,如:如:color=red;if(color=red)printf(red);由于枚举变量可以作为循环变量,因此可以利用循环和由于枚举变量可以作为循环变量,因此可以利用循环和switch语句打印全部的枚举值字符串。语句打印全部的枚举值字符串。【例【例9-21】输出全部的枚举值字符串】输出全部的枚举值字符串main()enum red,yellow,blue,white,blackcolor;printf(All enum strings are:n);for(color=red;color=black;color+)switch(color)case red:printf(redn);break;case yellow:printf(yellown);break;case blue:printf(bluen);break;case white:printf(whiten);break;case black:printf(blackn);break;9.3.3 枚举类型的应用枚举类型的应用main()enum daymon=1,tue,wed,thu,fri,sat,sunx;printf(Input a integer:n);scanf(%d,&x);switch(x)case mon:case tue:case wed:case thu:case fri:printf(Work dayn);break;case sat:case sun:printf(Rest dayn);break;default:printf(Input error!n);【例【例9-22】输入星期几的整数,输出】输入星期几的整数,输出“工作日工作日”或或“休息日休息日”的信息。的信息。9.4 用户定义类型用户定义类型1.定义定义“替代替代”类型名类型名定义的形式为:定义的形式为:typedef 类型名类型名 标识符;标识符;注注意意:“类类型型名名”必必须须是是系系统统提提供供的的数数据据类类型型或或用用户户已已定定义义的的数数据据类类型型。定定义义替替代代类类型型名名的的作作用用是是:给给已已有有的的类类型起个别名标识符,例如:型起个别名标识符,例如:typedef int INTEGER;2.定义定义“构造构造”类型名类型名定义的形式为:定义的形式为:typedef 类型名类型名 标识符及标识符及“构造构造”;注意:注意:“类型名类型名”必须是系统提供的数据类型或用户已必须是系统提供的数据类型或用户已定义的数据类型。定义构造类型名的作用是:自己定义新定义的数据类型。定义构造类型名的作用是:自己定义新“构造构造”类型名标识符。类型名标识符。举举 例例(1)定义字符型指针类型名定义字符型指针类型名CHARP typedef char*CHARP;以后可用它来定义指针变量,例如:以后可用它来定义指针变量,例如:CHARP p,q;即等价于:即等价于:char *p,*q;(2)定义具有定义具有3个元素的整型数组名个元素的整型数组名NUM typedef int NUM3;以后可用它来定义有三个元素的以后可用它来定义有三个元素的int型数组,如:型数组,如:NUM a,b,c;就相当于就相当于int a3,b3,c3;(3)定义某结构体类型名定义某结构体类型名STUDENT typedef str