第11章结构体和共用体青岛农业大学理信学院主要内容•一、结构体与结构体数组•二、共用体•三、枚举类型•四、typedef定义类型青岛农业大学理信学院一、结构体•例子:表示一个学生的信息,比如学号、姓名、性别、年龄等。•分别定义普通变量intnum;char*name;charsex;intage;无法反应出这些变量的内在联系。•构造类型的数据结构——数组??•结构体就是用于表示上述结构的数据结构。青岛农业大学理信学院•structstudent•{•intnum;•char*name;•charsex;•intage;•};关键字,表示以下定义一个结构体结构体类型的名字结构体的成员。定义方式与普通变量类似强调:student是一种类型,跟int,char,float等基本类型同等地位!!青岛农业大学理信学院声明结构体类型的一般形式•struct结构体名•{•成员1;•成员2;•……•};青岛农业大学理信学院定义student类型的变量(1)•structstudentstu1,stu2;•先声明结构体类型再定义变量青岛农业大学理信学院定义student类型的变量(2)在声明类型的同时定义变量•structstudent•{•intnum;•char*name;•charsex;•intage;•}stu1,stu2;一般形式:struct结构体名{成员表列}变量名表列;青岛农业大学理信学院定义student类型的变量(3)直接定义结构体类型变量•struct•{•intnum;•char*name;•charsex;•intage;•}stu1,stu2;一般形式:struct{成员表列}变量名表列;青岛农业大学理信学院例子:结构体变量的使用#include“stdio.h”voidmain(){structstudent{longintnum;char*name;charsex;intage;}stu1={10101,”LiLin”,’M’,21};printf(“No:%ld\n”,stu1.num);printf(“Name:%s\n”,stu1.name);printf(“Sex:%c\n”,stu1.sex);printf(“Age:%d\n”,stu1.age);}青岛农业大学理信学院结构体成员的引用•结构体变量名.成员名•其使用跟普通变量相同结构体变量的初始化•定义时初始化:•StructStudentstu1={10101,”LiLin”,’M’,19};•直接赋值:•stu1.num=10101;结构体数组•一个结构体变量中可以存放一组数据(如一个学生的学号、姓名、成绩等数据)。如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。•结构体数组与以前介绍过的数值型数组不同之处在于,每个数组元素都是一个结构体类型的数据,它们都分别包括各个成员(分量)项。结构体数组定义•structstudent•{intnum;•charname[20];•charsex;•intage;•floatscore;•};•structstudentstu[3];青岛农业大学理信学院结构体数组例子例11.2对候选人得票的统计程序。设有3个候选人,每次输入一个得票的候选人的名字,要求最后输出各人得票结果。#includestring.h#includestdio.hstructperson{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;j3;j++)if(strcmp(leader_name,leader[j].name)==0)leader[j].count++;for(i=0;i3;i++)printf(“%s:%d\n”,leader[i].name,leader[i].count);}指向结构体类型的指针•一个结构体变量的指针就是该变量所占据的内存段的起始地址。•可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。例子•stuctstudentstu;•structstudent*p=&stu;•使用指针变量引用结构体的成员:•(*p).num=10110;•(*p).age=18;•p-age=18;其中,-称为指向运算符以下三种形式等价:•结构体变量.成员名•(*p).成员名•p-成员名指向结构体数组的指针•指针变量也可以用来指向结构体数组中的元素。•structstudentstu[3],*p;•p=stu;或者p=&stu[0];•for(p=stu;pstu+3;p++)•printf(“%d%s%c%d”,p-num,p-name,p-sex,p-age)链表——动态存储结构•存储学生信息:结构数组•缺点:长度需要足够大,以便能够存放任何班级的学生数据,会造成内存空间的浪费A1356B1475C1021DNULL13561475102112491249head链表结点的结构structnode{charch;structnode*next;}生成链表structnodea,b,c,d,*head;a.ch=‘A’;b.ch=‘B’;c.ch=‘C’;d.ch=‘D’;head=&a;a.next=&b;b.next=&c;c.next=&d;d.next=NULL;访问链表structnode*p;p=head;while(p!=NULL){printf(“%c”,p-ch);p=p-next;}动态链表:根据需要创建结点•动态分配结点的存储单元•malloc•calloc•free(1)malloc函数•其函数原型为void*malloc(unsignedintsize);•其作用是在内存的动态存储区中分配一个长度为size的连续空间。•此函数的值(即“返回值”)是一个指向分配域起始地址的指针(类型为void)。如果此函数未能成功地执行(例如内存空间不足),则返回空指针(NULL)。(2)calloc函数•其函数原型为void*calloc(unsignedn,•unsignedsize);•其作用是在内存的动态存储区中分配n个长度为size的连续空间。•函数返回一个指向分配域起始地址的指针;如果分配不成功,返回NULL。•用calloc函数可以为一维数组开辟动态存储空间,n为数组元素个数,每个元素长度为Size。•注意malloc和calloc返回的指针都是void指针,使用时需要强制类型转换。(3)free函数•其函数原型为voidfree(void*p);•其作用是释放由p指向的内存区,使这部分内存区能被其他变量使用。p是最近一次调用calloc或malloc函数时返回的值。•free函数无返回值。实例:链表动态生成青岛农业大学理信学院二、共用体uniondatauniondata{inti;{inti;charch;或charch;floatf;floatf;}a,b;};uniondataa,b;青岛农业大学理信学院共用体类型变量•特点:成员共享同一段内存,即从同一地址开始。•在某一确定时刻,只有一个成员可用。ichf1000青岛农业大学理信学院例子#includestdio.hvoidmain(){uniondata{inti;charc;floatf;}a;a.i=10;a.c='a';a.f=1.2;printf(%d\n,a.i);printf(%c\n,a.c);printf(%f’\n,a.f);}例11.12使用一个结构表示教师和学生。#includestdio.hstruct{intnum;charname[10];charsex;charjob;union{intbanji;charposition[10];}category;}person[2];/*先设人数为2*/11.8共用体voidmain(){inti;for(i=0;i2;i++){scanf(%d%s%c%c,&person[i].num,&person[i].name,&person[i].sex,&person[i].job);if(person[i].job=='S')scanf(%d,&person[i].category.banji);elseif(person[i].job=='T')scanf(%s,person[i].category.position);elseprintf(“Inputerror!”);}printf(\n);printf(No.namesexjobclass/position\n);for(i=0;i2;i++){if(person[i].job=='S')printf(“%-6d%-10s%-3c%-3c%-6d\n”,person[i].num,person[i].name,person[i].sex,person[i].job,person[i].category.banji);elseprintf(“%-6d%-10s%-3c%-3c%-6s\n”,person[i].num,person[i].name,person[i].sex,person[i].job,person[i].category.position);}}运行情况如下:101LifsWangmtNo.Namesexjobclass/position101Lifs501102Wangmtprofessor青岛农业大学理信学院三、枚举类型enumweekday{sun,mon,tre,wed,thu,fri,sat};enumweekdayworkday,weekend;或者enumweekday{sun,mon,tre,wed,thu,fri,sat}workday;枚举元素或者枚举常量青岛农业大学理信学院枚举类型变量的使用•workday=mon;青岛农业大学理信学院注意1•枚举元素在C编译器中是按常量处理的,不是变量。•Mon=1;错!青岛农业大学理信学院注意2•枚举元素是有值的,按照定义的顺序分别是0,1,2,……•workday=mon;•该变量的值应为1。•enumweekday{sun=7,mon,tre,wed,thu,fri,sat};青岛农业大学理信学院注意3•枚举元素可以按照其数值的大小用作判断和比较•If(workday==mon)……青岛农业大学理信学院注意3•整数不能直接赋值给一个枚举变量,需要强制类型转换•workday=(enumweekday)2;青岛农业大学理信学院例11.13:五种颜色的球,从中取颜色不一样的三个球的排列组合,并输出。#includestdio.hmain(){enumcolor{red,yellow,blue,white,black};enumcolori,j,k,pri;intn,loop;n=0;for(i=red;i=black;i++)for(j=red;j=black;j++)if(i!=j){for(k=red;k=black;k++)if((k!=i)&&(k!=j)){n=n+1;printf(%-4d,n);for(loop=1;loop=3;loop++){switch(loop){case1:pri=i;break;case2:pri=j;break;case3:pri=k;break;default:break;}switch(pri){casered:printf(%-10s,red);break;caseyellow:printf(%-10s,yellow);break;caseblue:printf(%-10s,blue);break;casewhite:prin