310 likes | 399 Views
第 11 章 结构体与共用体. 本章教学内容: 11 .1 概述 11 .2 定义结构体类型变量的方法 11 .3 结构体变量的引用 11 .4 结构体变量的初始化 11.5 结构体数组 11.6 指向结构体类型数据的指针 11.7 用指针处理链表 11.8 共用体 11.9 枚举类型 11.10 用 typedef 命名已有类型. 本章教学内容: 结构体定义与引用 结构体数组 链表. 11.1 概述.
E N D
第11章 结构体与共用体 • 本章教学内容: • 11.1 概述 • 11.2 定义结构体类型变量的方法 • 11.3 结构体变量的引用 • 11.4 结构体变量的初始化 • 11.5 结构体数组 • 11.6 指向结构体类型数据的指针 • 11.7 用指针处理链表 • 11.8 共用体 • 11.9 枚举类型 • 11.10 用typedef命名已有类型 • 本章教学内容: • 结构体定义与引用 • 结构体数组 • 链表 计算机工程学院 伍俊明
11.1 概述 • 许多情况下,需要将不同类型的数据组合成一个整体,如一个学生有学号、姓名、性别、年龄、地址等属性。 • C语言允许构造结构体类型,以处理这类数据,如: Numname sex age score addr 100101 Li Fun M 18 87.5 Beijing struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }; 结构体 类型名 类型名 成员名 或域名 计算机工程学院 伍俊明
11.1 概述 • 结构体类型定义的一般形式: struct 结构体类型名 { 类型1 成员名1; 类型2 成员名2; …… 类型n 成员名n; }; 计算机工程学院 伍俊明
100101 ZhangXin M 19 90.5 Shanghai 100102 WangLi F 20 98 Beijing 11.2 定义结构体变量的方法 • 定义结构体变量有三种方法 一、先声明结构体类型,再定义结构体变量 • 例:struct student1, student2; • 定义student1、student2两个变量后系统为它们分配存储单元,每个变量至少占用59字节空间(=2+20+1+2+4+30) • 需要注意,定义结构体类型与定义结构体变量是两个不同的概念,结构体类型好比整型int,而结构体变量好比是整型变量i、j、k。 • 本方法值得推荐:先定义结构体类型,再定义结构体变量。 student1 student2 计算机工程学院 伍俊明
11.2 定义结构体变量的方法 二、在声明结构体类型的同时定义结构体变量 • 定义形式 struct 结构体类型名 { 类型1 成员名1; 类型2 成员名2; …… 类型n 成员名n; } 结构体变量名列表; • 这种“二合一”的方式也是很好的方法,也推荐使用。 例: struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; } student1, student2 ; 计算机工程学院 伍俊明
11.2 定义结构体变量的方法 三、直接定义结构体变量 • 定义形式 struct { 类型1 成员名1; 类型2 成员名2; …… 类型n 成员名n; } 结构体变量名列表; • 说明:这种方法未定义类型名,以后无法再引用类型名,建议尽量不使用本方法。 例: struct { int num; char name[20]; char sex; int age; float score; char addr[30]; } student1, student2 ; 无类型名
birthday addr num name sex age Month day year 11.2 定义结构体变量的方法 • 结构体成员也可以是结构体 struct date { int month; int day; int year; }; struct { int num; char name[20]; char sex; int age; struct date birthday; char addr[30]; } student1, student2 ; addr 计算机工程学院 伍俊明
11.3 结构体变量的引用 • 结构体变量的使用原则 • 结构体变量不能作为整体进行输入、输出 Printf(“%d,%s,%c,%d,%f,%s\n”, student1); • 结构体变量的成员可以视为所属类型的变量进行处理 student1.score=student2.score; sum=student1.score+student2.score; • 如结构体变量的成员也是结构体类型的,需逐级地处理其下层的各个成员 student1.birthday.month=12; scanf(“%d”, &student1.birthday.year); stuent1.age++; 计算机工程学院 伍俊明
11.4 结构体变量的初始化 • 变量在定义时也可以初始化 #include <stdio.h> main() { struct student { long int num; char name[20]; char sex; char addr[20]; } a={89031, "Li Lin", 'M', "123 Beijing Road"}; printf("NO.:%ld\nname:%s\nsex:%c\naddress:%s\n", a.num,a.name,a.sex,a.addr); } 运行结果: No.:10101 name:LiLin sex:M address:123 Beijing Road 计算机工程学院 伍俊明
11.5 结构体数组 • 尽管结构体变量包含了若干成员,但结构体类型的数据也可作为数组元素,构成结构体数组。 11.5.1 定义结构体数组 • 结构体数组定义与其它类型的数组定义方法相仿 • 例: struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }; struct student stu[3]; 计算机工程学院 伍俊明
11.5 结构体数组 11.5.2 结构体数组的初始化 • 结构体数组也可以象其它数组一样初始化。 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; } stu[2]= {{10101,″LiLin″,′M′,18,87.5,″103 BeijingRoad″}, {10102,″Zhang Fun″,′M′,19,99,″130 Shanghai Road″}}; • 数组初始化也可以采用下面形式: struct student stu[]={{…}, {…},…{…}}; 计算机工程学院 伍俊明
11.5 结构体数组 运行结果: Li↙ Fun↙ Zhang↙ Zhang↙ Fun↙ Li↙ Fun↙ Zhang↙ Li↙ Li:4 Zhang:3 Fun:3 void main() { int i,j; char leader_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++; } /*for*/ printf("\n"); for(i=0;i<3;i++) printf("%5s:%d\n",leader[i].name, leader[i].count); } /*main*/ 11.5.3 结构体数组应用举例 • 例:对候选人得票进行统计。设有3个候选人,每次输入一人得票候选人名字,输出各人的得票结果。 #include <stdio.h> #include <strint.h> struct person { char name[20]; int count; } leader[3]={"Li", 0, "Zhang", 0, "Fun", 0}; 计算机工程学院 伍俊明
11.6 指向结构体类型数据的指针 • 指针也可以指向结构体类型的变量,以及结构数组中的元素。 11.6.1 指向结构体变量的指针 • 指向结构体变量的指针的定义 struct 结构体类型 *指针变量名列表; • 例:struct student stu_1, *p; • 结构体指针变量的使用 p=&stu_1; stud_1.num=89101; strcpy(p->name, “Li Lin”); p->sex=‘M’; (*p).score=89.5; • 结构体变量的访问方法 • 结构体变量.成员名 • (*结构体变量的指针).成员名 • 结构体变量的指针->成员名 #include <stdio.h> #include <strint.h> struct student { long num; char name[20]; char sex; float score; } p *p 89101 “Li Lin” ‘M’ 89.5 计算机工程学院 伍俊明
void main() { struct student*p; printf("No. Name sex age\n"); for (p=stu;p<stu+3;p++) printf("%5d %-20s %2c %4d\n", p->num, p->name, p->sex, p->age); } 11.6 指向结构体类型数据的指针 11.6.2 指向结构体数组元素的指针 • 结构体变量的指针也可以指向结构体数组中的元素,例11.4 #include <stdio.h> struct student { int num; char name[20]; char sex; int age; }; struct student stu[3]= {{10101,"Li Lin",'M',18}, {10102,"Zhang Fun",'M',19}, {10104,"Wang Min",'F',20} }; p 10101 Li Lin Stu[0] ‘M’ 18 P’ 10102 Zhang Fun Stu[1] M 19 P’’ 10104 Wang Min Stu[2] F 计算机工程学院 伍俊明 20
11.6 指向结构体类型数据的指针 11.6.3 用结构体变量和指向结构体变量的指针作函数参数 • 将一个结构体变量的值传递给一个函数,有三种方法: • 用结构体变量的成员作参数——传值 • 用结构体变量作实参——传值 • 用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参——传地址,推荐使用 • 例11.5、11.6 有一个结构体变量,内含学生学号、姓名和3门课程成绩,要求在main函数中赋值,在另一函数中输出。 对字符串变量或成员赋值,需要使用strcpy函数。 计算机工程学院 伍俊明
11.7 用指针处理链表 11.7.1 链表概述 • 链表是一种重要的动态数据结构,能够根据需要动态地分配和回收存储单元,适用于元素个数不明确或不固定的情形。 • 链表是通过指针将若干数据元素(也称结点)按一定原则连接起来的,如下图: • 链表的结点:存放有用户数据,也有指向下一结点的指针,两类数据类型不一,因此,是一种结构体类型的。 • 链表的有一个“头指针”,存放第一个结点的地址,指向第一个结点。 • 链表中各个结点所使用的存储空间可以是不连续的。 计算机工程学院 伍俊明
11.7 用指针处理链表 • 链表结点的定义 • 若A、B、C、D分别表示四个学生的学号和成绩,定义如下 struct student { int num; float score; struct student *next; /*定义指向下一结点的指针域*/ } 计算机工程学院 伍俊明
11.7 用指针处理链表 11.7.2 简单链表的建立与输出 运行结果: 1010189.5 1010390.0 1010785.0 #include <stdio.h>#define NULL 0 struct student{ long num; float score; struct student *next; };void main() { struct student a, b, c, *head, *p; head=&a; a. num=99101; a.score=89.5; a.next=&b; b. num=99103; b.score=90; b.next=&c; c. num=99107; c.score=85; c.next=NULL; p=head; do {printf("%ld %5.1f\n",p->num,p->score); p=p->next; } while(p!=NULL); } 计算机工程学院 伍俊明
11.7 用指针处理链表 11.7.3 处理动态链表所需的函数 • malloc函数 • 函数原型: • 函数功能: 申请长度为size连续存储区,返回其始址 • calloc函数 • 函数原型: • 函数功能:为一维数组的元素分配n个长度为size的存储空间,返回其始址 • free函数 • 函数原型: • 函数功能:释放指针p所指的动态存储区 void *malloc(unsigned int size) void *calloc(unsigned n, unsigned size) void free(void *p) 计算机工程学院 伍俊明
11.7 用指针处理链表 struct student *creat() { struct student *head, *p1, *p2; n=0; p1=p2=( struct student*) malloc(LEN); scanf("%ld,%f",&p1->num,&p1->score); head=NULL; while(p1->num!=0) { n=n+1; if(n==1) head=p1; else p2->next=p1; p2=p1; p1=(struct student*)malloc(LEN); scanf("%ld,%f",&p1->num,&p1->score); } /*while*/ p2->next=NULL; return(head); } 11.7.4 建立动态链表 #include <stdio.h> #include <malloc.h> #define NULL 0 #define LEN sizeof(struct student) struct student { long num; float score; struct student *next; }; int n; 计算机工程学院 伍俊明
11.7 用指针处理链表 11.7.5 输出链表——依次输出各个结点中的数据 void print(struct student *head) { struct student *p; printf("\nNow,These %d records are:\n",n); p=head; if (head!=NULL) do{ printf("%ld %5.1f\n",p->num,p->score); p=p->next; /*指针后移一个结点*/ } while(p!=NULL); } 计算机工程学院 伍俊明
11.7 用指针处理链表 11.7.6 对链表的删除操作——删除满足条件的结点 struct student *del(struct student *head,long num) { struct student *p1,*p2; if (head==NULL){printf("\nlist null!\n"); goto end;} p1=head; while(num!=p1->num && p1->next!=NULL) {p2=p1;p1=p1->next;} /*寻找待删除的元素*/ if(num==p1->num) { /*查找成功*/ if (p1==head) head=p1->next; /*待删除的结点是头结点*/ else p2->next=p1->next; printf("delete:%ld\n",num);n=n-1; }else printf(“%ld not been found!\n”,num); /*查找失败*/ end:return(head); } 计算机工程学院 伍俊明
11.7 用指针处理链表 11.7.7 对链表的插入操作——将结点插入到链表中合适位置 • 在按学号从小到大排序的链表中插入新学员信息,保持有序 struct student *insert(struct student *head, struct student *stud) { struct student *p0,*p1,*p2; p1=head; p0=stud; if (head==NULL) {head=p0; p0->next=NULL;} /*新元素作为头结点*/ else { while((p0->num>p1->num) && (p1->next!=NULL)) {p2=p1; p1=p1->next;} /*while语句用于找到合适的位置*/ if (p0->num<=p1->num) { /*新结点应该插入到链表的中间*/ if(head==p1) head=p0; else p2->next=p0; p0->next=p1;} else {p1->next=p0; p0->next=NULL;} /*新元素插入到链尾*/ } /*if (head)*/ n=n+1; return(head); } 计算机工程学院 伍俊明
11.7 用指针处理链表 11.7.8 对链表的综合操作(将建立、输出、删除、插入) void main() { struct student *head,*stu; long del_num;printf("input records:\n"); head=creat(); print (head); printf("\ninput the deleted number:"); scanf("%ld",&del_num); while (del_num!=0) { head=del(head,del_num); print (head); printf ("input the deleted number:"); scanf("%ld",&del_num);} printf("\ninput the inserted record:"); stu=(struct student *) malloc(LEN); scanf("%ld,%f",&stu->num,&stu->score); while(stu->num!=0){ head=insert(head,stu); printf("input the inserted record:");stu=(struct student *)malloc(LEN); scanf("%ld,%f",&stu->num,&stu->score); } } 计算机工程学院 伍俊明
11.8 共用体 一、共用体:将不同类型的变量存放在同一段存储单元中 • 定义形式: • 例:union data { int i; char ch; float f; } a, b, c; • 说明: • 每个共用体变量占用4字节 • 每个变量只能存放其中一个成员 • 变量的内容为最后一次保存的值 union 共用体类型名 { 类型1 成员1;…;类型n 成员n; } 变量名列表; 计算机工程学院 伍俊明
11.8 共用体 二、共用体变量的引用方式 • 举例: a.i, a.f, b.ch, c.f 三、共用体类型数据的特点 • 不同类型的成员竞争使用同一存储区 • 共用体变量只保存最后存入的值 例:a.i=1; a.ch=‘a’; a.f=1.5; 执行这三个语句后a中只有f的值 • 共用体各成员的地址都相同:&a、&a.i、&a.ch、&a.f相同 • 共用体变量不能作为函数参数,函数返回值不许是共用体变量,但可以返回指向共用体变量的指针 • 共用体的成员可以是结构体类型的,结构体成员也可以是共用体类型的 共用体变量名.成员名 计算机工程学院 伍俊明
11.8 共用体 • 例11.12 设有若干个人员的数据,其中有学生和教师。学生的数据中包括:姓名、号码、性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。可以看出,学生和教师所包含的数据是不同的。现要求把它们放在同一表格中。 计算机工程学院 伍俊明
11.9 枚举类型 • 枚举类型:将变量的值一一列举出来,每个值是标识符。 • 枚举类型定义的一般形式: • 例:enum weekday{sun,mon,tue,wed,thu,fri,sat} enum weekday workday, week_end; workday=mon; week_end=sun; • 说明: • 枚举值都是标识符,按常量来处理,不能对它赋值 • 每个枚举值都有一个编号,默认值从0开始,依次增1,也可改变:enum weekday={sun=7, mon=1,tue,wed,thu,fri,sat} workday, week_end; • 枚举值可依据其编号大小进行比较。 enum 枚举类型名{标识符1,… , 标识符n} 计算机工程学院 伍俊明
11.9 枚举类型 • 例:11.13 口袋中有红、黄、蓝、白、黑5种颜色的球若干个。每次从口袋中先后取出3个球,问得到3种不同色的球的可能取法,输出每种排列的情况。 计算机工程学院 伍俊明
11.10 用typedef命名已有类型 • C语言允许用户用typedef为数据类型重新命名 • 例:typedef int INTEGER; typedef struct {int month; int day; int year;}DATE; INTEGER i, j; DATE birthday, *p; • 例:typedef int NUM[100]; /*声明NUM为整型数组类型*/ NUM n; /*定义n为整型数组变量*/ • 例:typedef char *STRING;/*STRING为字符指针类型*/ STRING p, s[10]; /*p为指针变量,s为指针数组*/ • 例:typedef int (*POINTER)(); /*POINTER为函数指针类型*/ POINTER p1, p2; /*p1、p2为POINTER类型的指针变量*/ typedef 数据类型 类型名; 计算机工程学院 伍俊明
第11章 结构体与共用体 • 作业(P318) • 11.2 • 11.3 • 11.5 • 11.9 • 11.11 计算机工程学院 伍俊明