第十讲 结构体和共用体

42
第第第 第第 第第第第 体体 第第第第第第第第第第第第第第第

description

第十讲 结构体和共用体. 合肥师范学院计算机科学与技术系. 思考一个问题. 在程序里表示一个人(姓名、年龄、性别、 …… ),怎么表示? 想表示多个人呢? 如何用计算机程序实现下述表格的管理?. 表 1 某学校学生成绩管理表. 数组的解决方法. int studentId[30]; /* 最多可以管理 30 个学生 , 每个学生的学 号用数组的下标表示* / charstudentName[10][30]; charstudentSex[2][30]; - PowerPoint PPT Presentation

Transcript of 第十讲 结构体和共用体

Page 1: 第十讲    结构体和共用体

第十讲 结构体和共用体合肥师范学院计算机科学与技术系

Page 2: 第十讲    结构体和共用体

思考一个问题 在程序里表示一个人(姓名、年龄、性别、……),怎么

表示? 想表示多个人呢? 如何用计算机程序实现下述表格的管理?

表 1 某学校学生成绩管理表

学号 姓名 性别 入学时间 计算机原

理 英 语 数 学 音 乐

1 令狐冲 男 1999 90 83 72 82

2 林平之 男 1999 78 92 88 78

3 岳灵珊 女 1999 89 72 98 66

4 任莹莹 女 1999 78 95 87 90

5 … …

6 … …

Page 3: 第十讲    结构体和共用体

数组的解决方法int studentId[30]; /* 最多可以管理 30 个学生 , 每个学生

的学 号用数组的下标表示 */char studentName[10][30];char studentSex[2][30];int timeOfEnter[30]; /* 入学时间用 int 表示 */int scoreComputer[30];/* 计算机原理课的成绩 */int scoreEnglish[30]; /* 英语课的成绩 */int scoreMath[30]; /* 数学课的成绩 */int scoreMusic[30]; /* 音乐课的成绩 */

Page 4: 第十讲    结构体和共用体

数组的解决方法 数据的内存管理方式

90788978

……

83927295

……

72889887

……

82786690

……

1

234

……

令狐冲林平之岳灵珊任莹莹

……

男男女女

……

1999199919991999……

Page 5: 第十讲    结构体和共用体

数组的解决方法 分配内存不集中,寻址效率不高 对数组进行赋初值时,容易发生错位 结构显得比较零散,不容易管理

Page 6: 第十讲    结构体和共用体

希望的内存分配图 1

令狐冲男

1999

90

83

72

82

2

林平之男

1999

78

92

88

78

3

岳灵珊女

1999

89

72

98

66

4

任莹莹女

1999

78

95

87

90

Page 7: 第十讲    结构体和共用体

1.15.1 结构的概念 struct STUDENT

{int studentID; /* 每个学生的序号 */

char studentName[10]; /* 每个学生的姓名 */ char studentSex[4]; /* 每个学生的性别 */ int timeOfEnter; /* 每个学生的入学时间 */ int scoreComputer; /* 每个学生的计算机原理成绩

*/ int scoreEnglish; /* 每个学生的英语成绩 */ int scoreMath; /* 每个学生的数学成绩 */ int scoreMusic; /* 每个学生的音乐成绩 */

};

结构:构造数据类型,把有内在联系的不同类型的数据统一成一个整体,使它们相互关联

结构又是变量的集合,可以单独使用其成员

Page 8: 第十讲    结构体和共用体

1.15.2 结构的定义

结构类型定义的一般形式为: struct 结构名 {

类型名 结构成员名 1 ; 类型名 结构成员名 2 ; 类型名 结构成员名 n ; }; 结构的定义以分号结束,

被看作一条语句

关键字 struct 和它后面的结构名一起组成一个新的数据类型名

Page 9: 第十讲    结构体和共用体

1.15.2 结构定义示例

定义平面坐标结构:struct point {

double x;

double y;

};

虽然 x 、 y 的类型相同,也可以用数组的方式表示,但采用结构体描述整体性更强,增加了程序的可读性,使程序更清晰。

Page 10: 第十讲    结构体和共用体

结构的嵌套定义

struct address{ char city[10]; char street[20]; int code; int zip;};

struct nest_friendslist { char name[10]; int age; struct address addr; char telephone[13]; } nest_friend;

在定义嵌套的结构类型时,必须先定义成员的结构类型,再定义主结构类型。

姓名 性别 年龄 通信地址 联系电话

电子邮箱城市 街道 门牌号 邮编

Page 11: 第十讲    结构体和共用体

1.15.2 结构变量的定义

三种定义结构变量的方式: 1. 单独定义

先定义结构类型,再定义具有这种结构类型的变量 struct friends_list{ char name[10]; /* 姓名 */ int age; /* 年龄 */ char telephone[13]; /* 联系电话 */}; struct friends_list friend1, friend2;

Page 12: 第十讲    结构体和共用体

结构变量的定义2. 混合定义在定义结构体类型的同时定义结构体变量

struct friends_list{char name[10]; int age; char telephone[13]; } friend1, friend2;

3. 无类型名定义在定义结构体变量时省略结构体名

struct { char name[10]; int age; char telephone[13]; } friend1, friend2;

Page 13: 第十讲    结构体和共用体

1.15.4 结构变量的初始化

struct friends_list friend1 = {

"Zhang", 26, "0571-85171880 "

} ;

name age telephone ↓          ↓         ↓       

Zhang 26 0571-85271880

Page 14: 第十讲    结构体和共用体

结构变量的使用-整体赋值

具有相同类型的结构变量可以直接赋值。将赋值符号右边结构变量的每一个成员的值都赋给了左边结构

变量中相应的成员。 struct friends_list {

char name[10];

int age;

char telephone[13];

} friend1 = {Zhang",26, “0571-85271880”}, friend2;

friend2 = friend1;

Page 15: 第十讲    结构体和共用体

1.15.3 访问结构变量的成员变量

1. 结构变量成员的引用

结构变量名 . 结构成员名

friend1.age = 26;

strcpy(friend1.name, "Zhang San");

nest_friend.addr.zip

Page 16: 第十讲    结构体和共用体

2. 结构体指针 struct point

{int x;int y;

}; struct point pt; /* 定义结构体变量 */ struct point *ppt; /* 定义结构体指针 */ ppt = &pt; 怎样通过 pt 访问 pt 的成员?

pt.x = 0; /* 成员运算符 */ 怎样通过 ppt 访问 pt 的成员?

(*ppt).x = 0; ppt->x = 0; /* 指向运算符 */ 第二种更常用

x

y

pptpt

Page 17: 第十讲    结构体和共用体

struct STUDENT{

int studentID;char studentName[10];char studentSex[4];struct date timeOfEnter;int scoreComputer;int scoreEnglish;int scoreMath;int scoreMusic;

}; struct STUDENT stu[30] = {{1," 令狐冲 "," 男 ",{1999,12,20},90,83,72,82}, {2," 林平之 "," 男 ",{1999,07,06},78,92,88,78}, {3," 岳灵珊 "," 女 ",{1999,07,06},89,72,98,66}, {4," 任莹莹 "," 女 ",{1999,07,06},78,95,87,90} };

初始化初始化1.15.5 结构体数组1.15.5 结构体数组

Page 18: 第十讲    结构体和共用体

结构体数组的指针 struct STUDENT *pt; pt = stu; …

2…

3…

4…

1stu[0]

stu[1]

stu[2]

pt

pt++

stu[3]

Page 19: 第十讲    结构体和共用体

for (pt=stu; pt<stu+30; pt++){

sum[0] = sum[0] + pt->scoreComputer; sum[1] = sum[1] + pt->scoreEnglish; sum[2] = sum[2] + pt->scoreMath; sum[3] = sum[3] + pt->scoreMusic;

}for (i=0; i<4; i++){ average[i] = sum[i]/4;

printf("%20s : %4.2f\n", name[i], *(average+i));

}

例 : 利用指向结构体数组的指针计算学生各科的平均成绩 例 : 利用指向结构体数组的指针计算学生各科的平均成绩

学号 姓名 性别入学时间 计算机

原理年 月 日 英语 数学 音乐

Page 20: 第十讲    结构体和共用体

例 8.2main(){

struct STUDENT *pt;float sum[4] = {0.0},average[4] = {0.0};int i;char *name[]={"score of Computer","score of English", "score of Math","score of Music"};

pt = stu; /*pt 指向结构体数组的第一个元素 */for (pt=stu; pt<stu+30; pt++){

sum[0] = sum[0] + pt->scoreComputer; sum[1] = sum[1] + pt->scoreEnglish; sum[2] = sum[2] + pt->scoreMath; sum[3] = sum[3] + pt->scoreMusic;

}for (i=0; i<4; i++){

average[i] = sum[i]/4; printf("%20s : %4.2f\n", name[i], *(average+i));

}}

Page 21: 第十讲    结构体和共用体

结构体与函数 向函数传递结构体的单个成员

单向值传递,函数内对结构内容的修改不影响原结构

向函数传递结构体的完整结构 单向值传递,函数内对结构内容的修改不影响原结

构,开销大 向函数传递结构体的首地址

用结构体数组或者结构体指针做函数参数 除提高效率外,还可以修改结构体指针所指向的结

构体的内容

Page 22: 第十讲    结构体和共用体

思考 下面的结构什么意思?

struct temp{

int data; struct temp pt;

} TC 下的错误提示:

Undefined structure ‘temp’ Structure size too large

VC 下的错误提示: ‘pt’ uses undefined struct ‘temp’

下面的的呢? struct temp

{ int data; struct temp *pt;

}

Page 23: 第十讲    结构体和共用体

动态数据结构 结构体声明时不能包含自我,但可以包含指向

本结构体类型的指针变量 链表( Linked table )struct Link

{ int data; struct Link *next;

}data nexthead data next data next data NULL

图 链表原理图

Page 24: 第十讲    结构体和共用体

共用体,或称为联合( Union ) union number{

short x;char ch;

float y;};

基本上和 struct 一样 x 、 ch 和 y 处于同样的地址 sizeof(union xxx) 取决于占空间最多的那个

成员变量

1000H

Page 25: 第十讲    结构体和共用体

共用体的特点 同一内存单元在每一瞬时只能存放其中一种类

型的成员;并非同时都起作用 起作用的成员是最后一次存放的成员 不能作为函数参数

Page 26: 第十讲    结构体和共用体

姓名name

性别sex

年龄age

家庭状况

婚姻状况标记

未婚 已婚

配偶

子女

structstruct person person{{ charchar name[20]; name[20]; charchar sex; sex; intint age; age; unionunion {{ intint single; single; structstruct {{ charchar spouseName[20]; spouseName[20]; intint child; child; }married;}married;}marital;}marital; intint marryFlag; marryFlag;

};};

共用体的应用共用体的应用

Page 27: 第十讲    结构体和共用体

学生信息管理链表程序解析

例 建立一个学生成绩信息(包括学号、姓名、成绩)的单向链表,学生记录按学号由小到大顺序排列,要求实现对成绩信息的插入、修改、删除和遍历操作。

main

InsertDoc DeleteDoc Print_Stu_Doc Create_Stu_Doc

InsertDoc

head 9905 Qian 80 NULL9901 Wang 80 9902 Li 90

Page 28: 第十讲    结构体和共用体

例 数据定义与函数声明

struct stud_node{ /* 链表结点类型 */ int num; char name[20]; int score; struct stud_node *next;};struct stud_node * Create_Stu_Doc(); /* 新建链表 */

struct stud_node * InsertDoc(struct stud_node * head, struct stud_node *stud); /* 插入 */

struct stud_node * DeleteDoc(struct stud_node * head, int num); /* 删除 */

void Print_Stu_Doc(struct stud_node * head); /* 遍历 */

Page 29: 第十讲    结构体和共用体

链表的概念

一种动态存储分布的数据结构若干个同一结构类型的“结点”依次串接而成 单向链表、双向链表

头指针 结点 尾结点

head 9903 Qian 80 NULL9901 Wang 80 9902 Li 90

Page 30: 第十讲    结构体和共用体

链表的概念-结点定义

struct stud_node{ int num; char name[20]; int score;

struct stud_node *next;};

结构的递归定义

head 9905 Qian 80 NULL9901 Wang 80 9902 Li 90

Page 31: 第十讲    结构体和共用体

链表的概念-与数组比较

数组 事先定义固定长度的数组 在数组元素个数不确定时,可能会发生浪费内存空间

的情况

链表 动态存储分配的数据结构 根据需要动态开辟内存空间,比较方便地插入新元素

(结点) 使用链表可以节省内存,提高操作效率

Page 32: 第十讲    结构体和共用体

动态存储分配函数 malloc()

void *malloc(unsigned size) 在内存的动态存储区中分配一连续空间,其长度为 size 若申请成功,则返回一个指向所分配内存空间的起始地

址的指针 若申请不成功,则返回 NULL (值为 0 ) 返回值类型: (void *)

通用指针的一个重要用途 将 malloc 的返回值转换到特定指针类型,赋给一个指针

Page 33: 第十讲    结构体和共用体

malloc() 示例

int *ip = (int *) malloc( sizeof(int) )

struct student * p;

p = (struct student *) malloc(sizeof(struct student));

调用 malloc 时,用 sizeof 计算存储块大小 虽然存储块是动态分配的,但它的大小在分配后也是确定

的,不要越界使用。

p

Page 34: 第十讲    结构体和共用体

动态存储释放函数 free

当某个动态分配的存储块不再用时,要及时将它释放

void free(void *ptr) 释放由动态存储分配函数申请到的整块内存空间, p

tr 为指向要释放空间的首地址。

free(ip);free(p);

p

Page 35: 第十讲    结构体和共用体

单向链表的常用操作

1. 链表的建立2. 链表的遍历3. 插入结点4. 删除结点

Page 36: 第十讲    结构体和共用体

1. 链表的建立struct stud_node *head, *tail, *p;head = tail = NULL;size = sizeof(struct stud_node);p = (struct stud_node *) malloc(size);

head

tail

tail

pnum name score next

p

Page 37: 第十讲    结构体和共用体

1. 链表的建立

Page 38: 第十讲    结构体和共用体

程序段 head = tail = NULL; scanf("%d%s%d", &num,name, &score); while(num != 0){ p = (struct stud_node *) malloc(size);

p->num = num; strcpy(p->name, name); p->score = score; p->next = NULL;

if(head == NULL) head = p; else tail->next = p; tail = p; scanf("%d%s%d", &num, name, &score); }

Page 39: 第十讲    结构体和共用体

2. 链表的遍历

ptr->num

ptr->score

ptr ptr

for(ptr = head; ptr != NULL; ptr = ptr -> next)

printf("%ld, %d", ptr -> num, ptr -> score);

ptr=ptr->next

head 9905 Qian 80 NULL9901 Wang 80 9902 Li 90

Page 40: 第十讲    结构体和共用体

链表的遍历-函数

void Print_Stu_Doc(struct stud_node * head) { struct stud_node * ptr; if(head == NULL){ printf("\nNo Records\n"); return; } printf("\nThe Students' Records Are: \n"); printf(" Num Name Score\n"); for(ptr = head; ptr!=NULL; ptr = ptr->next) printf("%8d %20s %6d \n", ptr->num, ptr->name, ptr->score);}

Page 41: 第十讲    结构体和共用体

s->next = ptr->next

ptr->next = s

先连后断

head

ptr

s

3. 插入结点

Page 42: 第十讲    结构体和共用体

ptr2=ptr1->next

ptr1->next=ptr2->next

head

ptr1 ptr2

free(ptr2)

先接后删

4. 删除结点

ptr2

head

ptr1