1 / 57

第 11 章结构体与共用体

第 11 章结构体与共用体. 11.1  概述 11.2  定义结构体类型变量的方法 11.3  结构体变量的引用 11.4  结构体变量的初始化 11.5  结构体数组 11.6  指向结构体类型数据的指针 11.7  用指针处理链表 11.8  共用体 11.9  枚举类型 11.10  用 typedef 定义类型. 大纲要求. ( 1 )掌握结构体和共用体类型的说明、结构体和共用体变量的定义及初始化方法 ( 2 )掌握结构体与共用体成员的引用 ( 3 )领会动态存储分配和释放 ( 4 )掌握链表的基本概念和基本操作 ( 5 )领会枚举类型变量的定义

krikor
Download Presentation

第 11 章结构体与共用体

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第11章结构体与共用体 11.1 概述 11.2 定义结构体类型变量的方法 11.3 结构体变量的引用 11.4 结构体变量的初始化 11.5 结构体数组 11.6 指向结构体类型数据的指针 11.7 用指针处理链表 11.8 共用体 11.9 枚举类型 11.10 用typedef定义类型

  2. 大纲要求 (1)掌握结构体和共用体类型的说明、结构体和共用体变量的定义及初始化方法 (2)掌握结构体与共用体成员的引用 (3)领会动态存储分配和释放 (4)掌握链表的基本概念和基本操作 (5)领会枚举类型变量的定义 (6)了解typedef的作用

  3. 11.1 概述 记录--由多种数据组成,如成绩册中每个学生的数据是一个记录,可以包括:学号、姓名及各科成绩 又如学生基本情况表中可以包括每个学生的:学号、姓名、性别、年龄、成绩、地址等。 C中实现记录的方法:使用结构体类型 struct student {int num; char name[20],sex; int age; float score; char addr[30]; };

  4. 结构体类型定义格式 结构类型定义 struct 结构体名 /* struct是结构类型关键字*/ {数据类型 数据项1;数据类型 数据项2; …… ……数据类型 数据项n; }; /* 此行分号不能少!*/ 例: 定义一个反映学生基本情况的结构类型,用以存储学生的相关信息。

  5. struct student {long num; char nname[20]; char sex; int age; float score; char addr[30]; }; struct date /*用于存放日期型数据*、 {int year; int month; int day; }; struct std_info /*学生信息结构类型:由学号、姓 {char no[7];    名、性别和生日共4项组成*/ char name[9]; char sex[3]; struct date birthday; }; struct score /*成绩结构类型:由学号和三门成绩共  {char no[7]; 4项组成*/ int score1; int score2; int score3; };

  6. (1)“结构类型名”和“数据项”的命名规则,与变量名相同。(1)“结构类型名”和“数据项”的命名规则,与变量名相同。 (2)数据类型相同的数据项,既可逐个、逐行分别定义,也可合并成一行定义。 例如,本例代码中的日期结构类型,也可改为如下形式: struct date {int year, month, day; }; (3)结构类型中的数据项,既可以是基本数据类型,也允许是 另一个已经定义的结构类型。 例如,本例代码中的结构类型std_info,其数据项“birthday”就是一个已经定义的日期结构类型date。 (4)本书将1个数据项称为结构类型的1个成员(或分量)。

  7. 11.2 定义结构体类型变量的方法 用户自己定义的结构类型,与系统定义的标准类型(int、char等)一样,可用来定义结构变量的类型。  定义结构变量的方法,可概括为3种: 1.间接定义法──先声明结构类型、再定义结构变量   一般格式为:struct 结构体名  结构体变量名表; 例如,利用例1中定义的学生信息结构类型std_info,定义了一个相应的结构变量student1: struct std_info student1; 结构变量student1:拥有结构类型的全部成员,其中birthday成员是一个日期结构类型,它又由3个成员构成。 结构体变量所占的存储空间为其各成员所占存储空间之和。 注意:使用间接定义法定义结构变量时,必须同时指定结构体名。

  8. 2.直接定义法──在定义结构类型的同时,定义结构变量2.直接定义法──在定义结构类型的同时,定义结构变量 例 struct student {int num; char name[20]; char sex; int age; float score; char addr[30]; }student1,student2; 同时定义结构类型及其结构变量的一般格式如下: struct 结构体名 { 成员表列 } 结构变量名表;

  9. 3.直接定义结构体类型变量 其一般格式如下: struct { 成员表列; } 结构变量表; struct student {int num; char name[20]; char sex; int age; float score; struct date birthday; char addr[30]; }student1,student2;

  10. 说明 (1)结构类型与结构变量是两个不同的概念,其区别如同int类型与int型变量的区别一样。编译时类型不占存储空间。 (2)结构类型中的成员名,可以与程序中的变量同名,它们代表不同的对象,互不干扰。 (3)成员可以是基本类型或构造类型(数组,结构体类型,共用体类型)、指针类型。

  11. 11.3 结构体变量的引用 结构体变量的引用规则: 1,对于结构变量,要通过成员运算符“.”,逐个访问其成员,且访问的格式为:    结构变量.成员  /*其中的“.”是成员运算符*/ 不能将一个结构体变量作为一个整体进行输入输出及其它运算 2,如果成员本身是一个结构体或共用体,则要用若干成员运算符,直到找到最低一级的成员为止。如在前面的例中对日期的引用为: student1.birthday.year, student1.birthday.month, student1.birthday.day 3,对结构体变量成员可以像普通变量一样进行各种操作。 4,可以引用结构体变量成员的地址。

  12. 11.4结构变量的初始化 结构变量初始化的格式,与一维数组相似: 结构变量={初值表} 不同的是:如果某成员本身又是结构类型,则该成员的初值为一个初值表。 例11.1 对结构体变量初始化 #include<stdio.h> void main(){ struct student {long int num; char name[20]; char sex; char addr[30]; }a={89031, "LiLin", 'M', "123Beijing Road"}; printf("NO:%ld\nname:%s\nsex:%c\naddress:%s\n",a.num,a.name,a.sex,a.addr);} 注意:初值的数据类型,应与结构变量中相应成员所要求的一致,否则会出错。

  13. 11.5 结构体数组 11.5.1 定义结构体数组     结构数组的每一个元素,都是结构类型数据,均包含结构类型的所有成员。   与结构变量的定义相似,结构数组的定义也分直接定义和间接定义两种方法,只需说明为数组即可。 struct student {int num; char nname[20]; char sex; int age; float score; char addr[30]; }stu[3]; struct student stu1[10];

  14. 11.5.2 结构体数组的初始化     与普通数组一样,结构数组也可在定义时进行初始化。初始化的格式为: 结构数组[n]={{初值表1},{初值表2},...,{初值表n}} 11.5.3 结构体数组应用举例 例11.2 对候选人得票的统计程序。设有3个候选人,每次输入一个得票候选人的名字,要求最后输出各得票结果。 #include<string> #include<stdio.h> struct person {char name[20]; int count; }leader[3]={"Li", 0, "Zhang", 0, "Fun",0};

  15. void main() {int i, j; char leader_name[20]; for(i=0;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(i=0;i<3;i++) printf("\n%5s:%d",leader[i].name,leader[i].count); }

  16. 11.6 指向结构体类型数据的指针 结构变量在内存中的起始地址称为结构变量的指针。 通过指向结构变量的指针来访问结构变量的成员,与直接使用结构变量的效果一样。一般地说,如果指针变量p已指向结构变量stu_1,则以下三种形式等价: (1) stu_1.成员 (2)(*p).成员 /* “*p”外面的括号不能省!*/ (3)p->成员 注意:在格式(1)中,分量运算符左侧的运算对象,只能是结构变量,;而在格式(2)中,指向运算符左侧的运算对象,只能是指向结构变量(或结构数组)的指针变量,否则都出错

  17. 例11.3 指向结构体变量的指针的应用 #include<string.h> #include<stdio.h> void main(){ struct student {long num; char name[20]; char sex; float score;}stu_1,*p; p=&stu_1; stu_1.num=89101; strcpy(p->name,"LiLin"); (*p).sex='M'; stu_1.score=89.5; printf("NO:%ld\n name:%s\n sex:%c\n score:%f\n", stu_1.num, stu_1.name, stu_1.sex, stu_1.score); printf("NO:%ld\n name:%s\n sex:%c\n score:%f\n", (*p).num, (*p).name, (*p).sex, (*p).score); }

  18. 11.6.2指向结构体数组的指针  如果指针变量p已指向某结构数组,则p+1指向结构数组的下 一个元素,而不是当前元素的下一个成员。   另外,如果指针变量p已经指向一个结构变量(或结构数组), 就不能再使之指向结构变量(或结构数组元素)的某一成员。

  19. 例11.4 指向结构体数组的指针的应用 #include<stdio.h> struct student {int num,age; char name[20],sex;}; struct student stu[3]={{10101,"Li Lin",'M',18}, {10102,"Zhang Fun",'M',19}, {10104,"Wang Min",'F',20}}; 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); }

  20. 11.6.3 用结构体变量主指向结构体的指针作函数参数 例11.5 有一个结构体变量stu,内含学生学号、姓名和3门课程成绩,要求在main函数中赋矛值,在另一函数print中将它们输出 要完成的工作: 建立结构体 定义结构体变量 给结构体变量赋值 调用函数输出 定义print函数

  21. #include<stdio.h> #include<string.h> struct student{ int num; char name[20]; float score[3];}; void main(){ void print(struct student); struct student stu; stu.num=12345; strcpy(stu.name,"Li Li"); stu.score[0]=67.5;stu.score[1]=89;stu.score[2]=78.6; print(stu);} void print(struct student stu){ printf("%d\n%s\n%f\n%f\n%f\n",stu.num,stu.name,stu.score[0], stu.score[1],stu.score[2]);}

  22. 例11.6 使用指向结构体变量的指针作为函数参数例11.6 使用指向结构体变量的指针作为函数参数 #include<stdio.h> #include<string.h> struct student{ int num; char name[20]; float score[3];}stu={12345,"Li Li",67.5,89,78.6}; void main(){ void print(struct student *); print(&stu);} void print(struct student *p){ printf("%d\n%s\n%f\n%f\n%f\n",p->num, p->name, p->score[0], p->score[1],p->score[2]);}

  23. 11.7 用指针处理链表 11.7.1 链表概述 1.链表结构 链表作为一种常用的、能够实现动态存储分配的数据结构,图11.10所示为单链表。一个链表有以下几个特点: • 头指针变量head──指向链表的首结点。 • 每个结点由2个域组成:1)数据域──存储结点本身的信息。2)指针域──指向后继结点的指针。 • 尾结点的指针域置为“NULL(空)”,作为链表结束的标志。

  24. 2.对链表的基本操作 对链表的基本操作有:创建、检索(查找)、插入、删除和修改等。 (1)创建链表是指,从无到有地建立起一个链表,即往空链表中依次插入若干结点,并保持结点之间的前驱和后继关系。 (2)检索操作是指,按给定的结点索引号或检索条件,查找某个结点。如果找到指定的结点,则称为检索成功;否则,称为检索失败。

  25. 在C语言中,用结构类型来描述结点结构。例如在C语言中,用结构类型来描述结点结构。例如 struct student {long num; /*用于存放学生的学号*/ float score;/*用于存放学生的成绩*/ struct student *next;/*指针域,用于存放下一个结点的地址*/ }

  26. 11.7.2 简单链表 例11.7 建立一个如图11.11所示的简单链表,它由3个学生数据的结点组成,输出各结点中的数据 算法设计: 1,建立结构体; 2,用3个结构体变量存储3个学生信息; 3,形成链表,并将其首结点的地址存放在头指针中 4,输出

  27. #include<stdio.h> #define NULL 0 struct student {long num; float score; struct student *next; }; main() {struct student a,b,c,*head,*next;*p; a.num=99101; a.score=89.5; b.num=99103; b.score=90; c.num=99107; c.score=85;

  28. head=&a; a.next=&b; b.next=&c; c.next=NULL; p=head; do {printf("%ld\t%5.1f\n",p->num,p->score); p=p->next; }while(p!=NULL); }

  29. 11.7.3处理动态链表所需的函数 1,malloc函数 函数原型: void *malloc(unsigned int size); 功能:在内存的动态存储区中分配一个长为size的连续空间。返回一个指向分配域起始地址的指针,指针类型为void 使用格式: 指针变量=(struct 结构体名 *)malloc(sizeof(struct 结构体名));

  30. 2,calloc函数 函数原型: void *calloc(unsigned n, unsigned size); 功能:在内存的动态存储区中分配n个长为size的连续空间,返回一个指向该空间的起始地址 3,free函数 函数原型: void free(void *p) 功能:释放由p所指向的内存区。 使用格式:free(p);

  31. 11.7.4 建立动态链表 基本思路:   首先向系统申请一个结点的空间,然后输入结点数据域的(2个)数据项,并将指针域置为空(链尾标志),最后将新结点插入到链表尾。对于链表的第一个结点,还要设置头指针变量。 算法设计: 1 定义结构体(含两个数据成员和一个指针成员) 2 定义结构体指针变量:head,p1,p2; 3 分配空间,并将其返回值赋给p1,p2; 4 输入新结点的数据 5 while(p1->num!=0) 5.1 将新结点插入链表中 5.2 分配空间,并将其返回值赋给p1,p2; 5.3 输入新结点的数据 6 返回head

  32. #include<stdio.h> #include<malloc.h> #define LEN sizeof(struct student) struct student {long num; float score; struct student *next;}; struct student *creat(void) /*一个返回链表指针的函数*/ { struct student *head, *p1, *p2; int n=0; p1=p2=(struct student*)malloc(LEN); scanf("%ld%f",&p1->num,&p1->score); head=NULL;

  33. while(p1->num!=0) {n++; if(n= =1) head=p1; else p2->next=p1; p2=p1; p1=(struct student*)malloc(LEN); scanf("%ld%f",&p1->num,&p1->score); } p2->next=NULL; return(head);}

  34. 11.7.5 输出链表   用结构体指针变量p指向其第一个结点,输出该结点的数 据,然后将其指向下一个结点,方法是:p=p->next,当p为 NULL时结束。 void print(struct student *head) {struct student *p; p=head; if(head!=NULL) do {printf("%ld %5.1f\n",p->num,p->score); p=p->next;}while(p!=NULL); }

  35. 11.7.6 对链表进行删除操作(删除学号为已知值的结点) 算法设计: 1 寻找要删除的结点, 2 删除结点。 head 要删除的结点为第一个结点 head

  36. 要删除的结点为中间结点 p2 p1 head head p2->next=p1->next

  37. 1 寻找要删除的结点, while(p1->next!=NULL&&p1->num!=num) {p2=p1;p1=p1->next;} 2 删除结点。(p1为要删除的结点,p2为要删除的结点的前一个结点。) if  要删除的结点为首结点,则只须修改head else p2->next=p1->next;

  38. struct student *del(struct student *head,long num) {struct student *p1,*p2; if(head= =NULL) return head; p1=head; while(p1->next!=NULL&&p1->num!=num) {p2=p1;p1=p1->next;} if(num= =p1->num) { if(p1= =head) head=p1->next; else p2->next=p1->next; } return head; }

  39. 11.7.7对链表的插入操作   使一个有序链表在插入后仍为有序链表 算法设计: 1,对空表的插入 2,查找插入点 3,插入 3.1 插入为头结点 3.2 插入为中间结点 3.3 插入为最后一个结点

  40. 插入为头结点 p0指向要插入的结点,将p0插入到p1 之前 e head=p0; p0->next=p1;

  41. ai-1 ai ai-1 e 插入为中间结点 p0指向要插入的结点,将p0插入到p2之后p1之前 p2 p1 p0 p0->next=p2->next p2->next=p0;

  42. ai-1 ai-1 e 插入为最后一个结点 p0指向要插入的结点,将p0插入到p1之后 p2 p0 p1->next=p0; p0->next=NULL;

  43. 例11.11 插入结点的函数insert 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;return(head);} while((p0->num>p1->num)&&p1->next!=NULL) //查找插入点 {p2=p1; p1=p1->next;}

  44. if(p0->num<=p1->num)//插入到p1之前 if(head==p1) //插入为头结点    {head=p0; p0->next=p1;} else//插入为中间结点 { p2->next=p0; p0->next=p1;} else //插入为最后一个结点 {p1->next=p0;p0->next=NULL;} return(head); }

  45. 11.7.8 对链表的综合操作 例:建立一个链表,实现按学号删除、插入结点和输出所有结点 目标:1,建立一个链表 2,按输入的学号删除相应的结点 3,插入多个结点 每一步操作完成后要查看结果

  46. 算法设计 S1:建立结构体和定义结构指针变量 S2:调用creat函数建立链表 S3:输出全部结点 S4:输入学号并调用del函数删除相应结点 S5:输出全部结点 S6:插入多个结点(当学号为0时结束) S7:输出全部结点

  47. 作业: • 编写一个程序使用动态链表实现下面的功能: • 建立一个链表用于存储学生的学号、姓名和三门课程的成绩和平均成绩 • 输入学号后输出该学生的学号、姓名和三门课程的成绩 • 输入学号后删除该学生的数据 • 插入学生的数据 • 输出平均成绩在80分及以上的记录 • 要求用循环语句实现2--5的多次操作

  48. 11.8 共用体 11.8.1 共用体的概念1,使几个不同的变量占用同一段内存空间的结构称为共用型。2,共用类型的定义 union 共用类型名{ 成员列表; }; 3, 共用变量的定义 union data {int i; char ch; float f;}a,b,c; 或 union data a,b,c;

  49. 11.8.2 共用体变量的引用方式 与结构变量一样,也只能逐个引用共用变量的成员 例如,访问共用变量a的 各成员的格式为:a.i , a.ch, a.f。

  50. 11.8.3 共用体类型的特点 (1)同一个内存段用来存放几种不同类型的成员,但在每一时刻只能存放其中的一种 (2)共用体变量中起作用的最后赋值的成员 例如,执行a.i=1, a.ch='c', a.f=3.14后,un1.f才是有效的成员。 (3)由于所有成员共享同一内存空间,故共用变量与其各成员的地址相同。 例如,&a=&a.i=&a.ch=&a.f。 (4)不能对共用体变量进行初始化(注意:结构变量可以) (5)不能将共用体变量作为函数参数,以及使函数返回一个共用体数据,但可以使用指向共用体变量的指针。 (6)共用体类型可以出现在结构类型定义中,反之亦然。

More Related