480 likes | 647 Views
第 9 章. 用户建立的数据类型. 本章要点. 结构体的概念 结构体的定义和引用 结构体数组. 在程序里表示一个人(姓名、年龄、性别、 …… ),怎么表示? 想表示多个人呢? 如何用计算机程序实现下述表格的管理?. 问题的提出. 表 1 某学校学生成绩管理表. int studentId[30] = {1,2,3,4,5,6}; char studentName[10][30] = {{" 令狐冲 "},{" 林平之 "}, {" 岳灵珊 "},{" 任莹莹 "}};
E N D
第9章 用户建立的数据类型 公共计算机基础教研部
本章要点 结构体的概念 结构体的定义和引用 结构体数组 公共计算机基础教研部
在程序里表示一个人(姓名、年龄、性别、……),怎么表示?在程序里表示一个人(姓名、年龄、性别、……),怎么表示? 想表示多个人呢? 如何用计算机程序实现下述表格的管理? 问题的提出 表1 某学校学生成绩管理表 公共计算机基础教研部
int studentId[30] = {1,2,3,4,5,6}; char studentName[10][30] = {{"令狐冲"},{"林平之"}, {"岳灵珊"},{"任莹莹"}}; char studentSex[2][30] = {{"男"},{"男"}, {"女"},{"女"}}; int timeOfEnter[30] = {1999,1999,1999,1999}; int scoreComputer[30] = {90,78,89,78}; int scoreEnglish[30] = {83,92,72,95}; int scoreMath[30] = {72,88,98,87}; int scorePhy[30] = {82,78,66,90}; 数组的解决方法 公共计算机基础教研部
struct STUDENT {int studentID; /*每个学生的序号*/ char studentName[10];/*每个学生的姓名*/ char studentSex[4]; /*每个学生的性别*/ int timeOfEnter; /*每个学生的入学时间*/ int scoreComputer; /*每个学生的计算机原理成绩*/ int scoreEnglish; /*每个学生的英语成绩*/ int scoreMath; /*每个学生的数学成绩*/ int scorePhy; /*每个学生的物理成绩*/ }; 【注:】structSTUDENT是一个类型 structSTUDENT students[4]; 【注:】students[0].studentName students[0].Sex 它们都是变量,一般称为结构的成员变量 结构体的解决方法 公共计算机基础教研部
结构体: 把关系紧密且逻辑相关的多种不同类型的变量组织到统一的名字之下,也称复合(构造)数据类型 这种类型的变量占用相邻的一段内存单元 共用体: 把情形互斥但又逻辑相关的多种不同类型的变量组织在一起 这种类型的变量占用同一段内存单元,因此每一时刻只有一个数据起作用 用户自定义的数据类型 公共计算机基础教研部
9.1结构体类型与结构体变量 结构名 struct structurename { datatype variable1; datatype variable2; ... }; 结构成员 C 语言中的有效数据类型 struct student { int num; char name[20]; char sex; float score; }; 公共计算机基础教研部 7
结构体类型的定义 struct student 结构体的定义只定义了数据的形式,即声明了一种复杂的数据类型,并未生成任何变量。 { int num; char name[20]; char sex; float score; }; 构成结构体的变量称为结构体的成员(member), 也称元素(element)或域(filed) 公共计算机基础教研部
结构变量的定义 I.先定义结构,再声明结构变量 struct student { int num; char name[20]; char sex; float score; }; struct student student1,student2; II.在定义结构类型的同时声明结构变量 struct student { int num; char name[20]; char sex; float score; }student1,student2; III. 直接声明结构变量 struct { int num; char name[20]; char sex; float score; }student1,student2; 声明一个类型为 student 结构的变量,将会为该变量分配内存,大小是大于或等于其所有成员变量的大小之和。 公共计算机基础教研部
一个结构变量的成员变量在内存中是相邻的 整个结构变量的将占用多少内存呢? 是所有成员变量的内存总和吗? 事实上,所有数据类型在内存中都是从偶数地址开始存放的,且结构所占的实际空间一般是按照机器字长对齐的 不同的编译器、不同的平台,对齐方式会有变化,不过一般的编译器都可以设定按照多大对齐 我们可以用sizeof来获得结构的大小 结构(Structure)的内存占用 结构体的总大小为结构体最宽基本类型成员大小的整数倍 公共计算机基础教研部
结构(Structure)的内存占用 struct stu { char c; char b; int a; } x; 若: struct stu { char b; int a; } x; sizeof( x)=? a c b a b 填充字节(trailing padding) 填充字节 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍 公共计算机基础教研部
结构(Structure)的内存占用 若: struct stu { char b; int a; chat c; } x; sizeof( x)=? sizeof( x)=12 a b c 填充字节 填充字节 结构体的总大小为结构体最宽基本类型成员大小的整数倍 公共计算机基础教研部
结构(Structure)的内存占用 struct stu { char b; int a; chat c; } x; 字节对齐问题: • 为什么需要字节对齐? • 这样有助于加快计算机的取数速度,否则就得多花指令周期了。 • 为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。 • 这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。 公共计算机基础教研部
结构(Structure)的内存占用 struct stu { char b; int a; chat c; } x; 总结: 1) 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding); 2) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。 公共计算机基础教研部
用typedef为已存在的类型定义新名字 structstudent { int num; char name[20]; char sex; int age; float score; char addr[30]; } ; typedefstruct student STUD; STUD student1,student2; 用STUD代替 structstudent类型; 结构体变量的定义 内容详见: 9.7 节 公共计算机基础教研部
可以改写成int year,mongth,day; 结构体的嵌套 日期结构体类型:由年、月、日三项组成 struct date { int year; int month; int day; }; 嵌套的结构体定义 struct std_info { int num ; char name[20]; char sex; float score; char addr[30]; struct date birthday; }; 学生信息结构类型:由学号、姓名、性别、成绩、地址和生日共6项组成 公共计算机基础教研部
结构体变量的引用 结构体变量的引用原则 结构体变量不能整体输入输出,要通过成员运算符“.”,逐个访问其成员,且访问的格式为: 结构体变量.成员 scanf(“%d”,&birth.year); scanf(“%d%d”,&birth.month,&birth.day); birth.year=1990; birth.month=8; birth.day=21; “.”是成员运算符,优先级最高 struct date { int year; int month; int day; }; struct date birth; printf("%d,%d,%d",birth); printf("%d,%d,%d",birth.year, birth.month,birth.day); 公共计算机基础教研部
结构体变量的引用 如果某成员本身又是一个结构类型,则只能通过多级的分量运算,对最低一级的成员进行引用。 结构变量.成员.子成员.….最低级子成员 struct date { int year; int month; int day; }; struct std_info { int num ; char name[20]; char sex; float score; struct date birthday; }student; 引用结构变量student中的birthday成员的格式分别为: student.birthday.year 对最低一级成员,可像同类型的普通变量一样,进行相应的各种运算。 student.birthday.month student.birthday.day 公共计算机基础教研部
结构体变量的初始化 一般形式 结构体类型名 结构体变量={初值表}; 说明 若某成员本身又是结构体类型,则该成员的初值为一个初值表 初值的数据类型,应与结构变量中相应成员的类型一致 struct std_info { int num ; char name[20]; char sex; float score; struct date birthday; }; struct std_info student={102, "Zhangsan", 'M', 85, {1980,9,20}} ; 公共计算机基础教研部
结构体变量的初始化 内存 student1 struct student { int num; char name[20]; char sex; float score; }; struct student student1,student2; 赋值的顺序应与成员声明时的顺序一样;允许初始化语句中的值的数目比结构成员数目少。 struct student student1={1,"Yao Ming ",'M',90.5}; 忽略填充字节 M 90.5 1 Yao Ming student1.name student1.num student1.score 公共计算机基础教研部 student1.sex
student2 student3 结构变量赋值 • 用输入语句或赋值语句来给结构变量的各个成员赋值 student2.num=1; student2.name="Zhang Zi Liang"; student2.sex=’M’; printf("请输入成绩:\n"); scanf("%f",&student2.score); strcpy(student2.name,”Zhang Zi Liang”); 78 student3 = student2; 1 Zhang Zi Liang 78 M 1 Zhang Zi Liang M 78 公共计算机基础教研部
struct std_info { int num ; char name[20]; char sex; struct date birthday; }; main(){ struct std_info stu={102, "Zhangsan", 'M', {1980,9,20}} ; printf("Num: %d\n",stu.num); printf("Name: %s\n",stu.name); printf("Sex: %c\n",stu.sex); printf("Birthday: %d-%d-%d\n",stu.birthday.year, stu.birthday.month, stu.birthday.day); } 使用结构示例 struct std_info stu; scanf("%d",&stu.num); scanf(“%s”,stu.name); .... scanf(“%d”,&stu.birthday.year); [例] 定义一个结构变量stu,用于存储和显示一个学生的基本情况。 公共计算机基础教研部
stu3 stu1 stu2 #include<stdio.h> struct student { int num;//学号 char *name;//姓名 char sex;//性别 float score;//成绩 }; void main() { struct student stu1={1,"李亚鹏",'M',61}; struct student stu2={2,"周晶晶",'F',92.5}; struct student stu3={3,"姚光明",'M',59}; printf("不及格学员的名单如下:\n"); if(stu1.score<60) printf("%d\t%s\t%c\t%5.2f\n",stu1.num,stu1.name,stu1.sex,stu1.score); if(stu2.score<60) printf("%d\t%s\t%c\t%5.2f\n",stu2.num,stu2.name,stu2.sex,stu2.score); if(stu3.score<60) printf("%d\t%s\t%c\t%5.2f\n",stu3.num,stu3.name,stu3.sex,stu3.score); if(stu1.score>=60 && stu2.score>=60 && stu3.score>=60) printf("没有不及格的学员。\n"); } 使用结构示例 李亚鹏 78 1 M 问题描述: 根据学员的成绩,输出不及格学员的详细信息。 周晶晶 92 2 F 姚光明 59 3 M 不及格学员的名单如下: 3 姚光明 M 59.00 公共计算机基础教研部
9.2 结构体数组 定义:结构数组的每一个元素,都是结构类型数据,均包含结构类型的所有成员。 struct student {int num ; char name[20]; char sex; int age; float score; }; struct student stu[3] ; stu[0] stu[1] stu[2] 公共计算机基础教研部
结构体数组 • 结构体数组初始化: 结构体类型名 结构体数组名[n]={{初值表1},{初值表2}, ...,{初值表n}}; struct student {int num ; char name[20]; char sex; int age; float score; }; struct student stu[3]={{101,"Lilin",'M',18,87.5}, {102,"Zhanghua",'M',18,99}, {103,'Wuli",'F',19,78.5}} ; 公共计算机基础教研部
name count 0 Jiu 0 ABian 0 Song 结构体数组 struct person { char name[20]; int count; }leader[3]={“Jiu”,0,“ABian”,0,”Song”,0}; 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(i=0;i<3;i++) printf("%5s:%d\n",leader[i].name,leader[i].count); } <例> 统计后选人选票 公共计算机基础教研部
struct point{ int x;int y; }; struct point pt; /*定义结构体变量*/ struct point *ppt; /*定义结构体指针*/ ppt = &pt; pt ppt x y 9.3 结构体指针 • 怎样通过pt访问pt的成员? • pt.x = 0; /*成员运算符*/ • 怎样通过ppt访问pt的成员? • (*ppt).x = 0; • ppt->x = 0; /*指向运算符*/ • 第二种更常用 公共计算机基础教研部
引用结构体变量成员的三种形式 若struct student stu; struct student *p=&stu;则 • 结构体变量.成员名 stu.num • (*p).成员名 (*p).num • p->成员名 p->num 公共计算机基础教研部 D
struct student { int num ; char name[20]; int age; }; main() { struct student stu; struct student *p=&stu; (*p).num=101; strcpy((*p).name,"lilin"); printf(“学号:%d,姓名:%s”, (*p).num,(*p).name); } p->num=101; strcpy(p->name,"lilin"); 公共计算机基础教研部
struct student *pt; pt = stu; 1 … 2 … 3 … 4 … 结构体数组的指针 struct student { int num ; char name[20]; int age; }; struct student stu[30]; pt stu[0] pt++ stu[1] stu[2] stu[3] 公共计算机基础教研部
<练>09年国二考题 有以下程序 #include <stdio.h> struct ord { int x,y;} dt[2]={1,2,3,4}; main() { struct ord *p=dt; printf("%d,", ++p->x); printf("%d\n", ++p->y); } 程序的运行结果是 A. 1,2 B. 2,3 C. 3,4 D.4,1 公共计算机基础教研部
<练>下面程序的输出结果为( )。struct st{ int x; int *y;} *p;int dt[4]={10,20,30,40};struct st aa[4]={50,&dt[0],60,&dt[1], 70,&dt[2],80,&dt[3]};main(){ p=aa;printf("%d\n",++p->x);printf("%d\n",(++p)->x);printf("%d\n",++(*p->y));}A.10 B.50 C. 51 D.60 20 60 60 70 20 21 21 31 10 20 30 40 50 60 70 80 x y aa dt p &dt[0] &dt[1] &dt[2] &dat[3] p++ 公共计算机基础教研部
例:求如下简表中,每科考试的平均分。 公共计算机基础教研部
例:求如下简表中,每科考试的平均分。 p struct student { int num; char name[20]; int scoreMath; int scorePhysic; int scoreComputer; int scoreEnglish; }; struct student stu[30]; struct student *p; p=stu; 公共计算机基础教研部
例:求如下简表中,每科考试的平均分。 p for(p=stu; p<stu+30;p++) { sum1+=p->scoreMath; sum2+=p->scorePhysic; sum3+=p->scoreComputer; sum4+=p->scoreEnglish; } 公共计算机基础教研部
向函数传递结构体的单个成员 单向值传递,函数内对结构内容的修改不影响原结构 向函数传递结构体的完整结构 单向值传递,函数内对结构内容的修改不影响原结构,开销大 向函数传递结构体的首地址 用结构体数组或者结构体指针做函数参数 除提高效率外,还可以修改结构体指针所指向的结构体的内容 9.3.3 结构体变量和指向结构体的指针 作函数参数 公共计算机基础教研部
struct date { int year; int month; int day; }; void func(struct datep) { p.year = 2000; p.month = 5; p.day = 22; } 结构体与函数 1999,4,23 1999,4,23 main() { struct date d; d.year = 1999; d.month = 4; d.day = 23; printf(“%d,%d,%d\n”, d.year, d.month, d.day); func(d); printf(“%d,%d,%d\n”, d.year, d.month, d.day); } 公共计算机基础教研部
struct date { int year; int month; int day; }; void func(struct date*p) { p->year = 2000; p->month = 5; p->day = 22; } 结构体与函数 1999,4,23 2000,5,22 main() { struct date d; d.year = 1999; d.month = 4; d.day = 23; printf(“%d,%d,%d\n”, d.year, d.month, d.day); func(&d); printf(“%d,%d,%d\n”, d.year, d.month, d.day); } 公共计算机基础教研部
# include <string.h>struct STU{ int num; float score; };void f(struct STU p){ struct STU s[2]={{2044,550},{2045,537}};p.num = s[1].num; p.score = s[1].score;}main(){ struct STU s[2]={{2041,703},{2042,580}};f(s[0]);printf("%d %3.0f\n", s[0].num, s[0].score);} <例>分析程序运行后的输出结果。 A)2045 537 B)2044 550 C)2042 580 D)2041 703 num score s p 537 2045 2041 703 2041 703 2042 580 s 2044 550 数组元素作实参 2045 537
struct STU { char name[10]; int num; };void f(char *name, int num){ struct STU s[2]={{“Sun”,2044},{“Li”,2045}};num = s[0].num;strcpy(name, s[0].name);}main(){ struct STU s[2]={{“Yang”,2041},{“Guo”,2042}},*p;p=&s[1]; f(p->name, p->num);printf("%s %d\n", p->name, p->num);} A)Sun 2042 B)Sun 2044 C)Guo 2042 D)Yang 2041 <例>分析程序运行后的输出结果。 name num s Yang 2041 p 2042 num 2044 name Guo 2042 Sun s Sun 2044 Li 2045
struct STU { char name[10]; int num; float score; };void f(struct STU *p){ struct STU s[2]={{"Sun",2044,550}, {"Peng",2045,537}}; struct STU *q=s;++p ; ++q; *p=*q;}main(){ struct STU s[3]={{“Yang”,2041,703},{“Li”,2042,580}};f(s);printf("%s %d %3.0f\n", s[1].name, s[1].num, s[1].score);} A)Sun 2044 550 B)Peng 2045 537 C)Li 2042 580 D)Sun 2041 703 <例>分析程序运行后的输出结果。 num score name s Yang 2041 703 p p Peng 2045 537 Li 2042 580 s q Sun 2044 550 q Peng 2045 537
<练>09年3月国二考题 下列程序的运行结果为【】。 struct A { int a; char b[100]; double c; }; void f(struct A *t) { strcpy(t->b,"ChangRong"); } main() { struct A a={1001, "ZhangDa", 1098.0}; f(&a); printf("%d,%s,%6.1f\n", a.a, a.b, a.c); } 公共计算机基础教研部
<练>08年4月国二考题。以下程序的运行结果是 typedef struct { char name[9]; char sex; float score[2]; } STU; void f( STU a) { STU b={“Zhao” ,’m’,85.0,90.0} ; int i; strcpy(a.name,b.name); a.sex=b.sex; for(i=0;i<2;i++) a.score[i]=b.score[i]; } main() { STU c={“Qian”,’f’,95.0,92.0}; f(c); printf(“%s,%c,%2.0f,%2.0f\n”,c.name,c.sex,c.score[0],c.score[1]); } A) Qian,f,95,92 B) Qian,m,85,90 C) Zhao,f,95,92 D) Zhao,m,85,90 公共计算机基础教研部
<练>08年4月国二考题: 以下程序中函数fun的功能是:统计person所指结构体数组中所有性别(sex)为M的记录的个数,存入变量n中,并做为函数值返回。请填空。 #define N 3 typedef struct { int num; char nam[10]; char sex;}SS; int fun(SS person[ ]) { int i,n=0; for(i=0;i<N;i++) if(【 】==’M’ ) n++; return n; } main() { SS W[N]={{1,”AA”,’F’},{2,”BB”,’M’},{3,”CC”,’M’}}; int n; n=fun(W); printf(“n=%d\n”,n); } 公共计算机基础教研部
data next data next data next data NULL head 链表原理图 9.4 用指针处理链表 链表 公共计算机基础教研部
编程练习 在屏幕上模拟显示一个数字式时钟 时:分:秒 定义一个时钟结构体类型: struct clock { int hour; int minute; int second; }; typedefstruct clock CLOCK; 公共计算机基础教研部
编程练习 void update(CLOCK *t) { t->second++; if (t->second==60) { t->second=0; t->minute++; } if (t->minute==60) { t->minute =0; t->hour++; } if (t->hour==24) t->hour=0; } void display(CLOCK *t) { printf("%2d:%2d:%2d\r", t->hour, t->minute, t->second); } 公共计算机基础教研部
编程练习 void Delay(void) { long t; for (t=0; t<50000000; t++) { /*循环体为空语句的循环,起延时作用*/ } } main() { long i; CLOCK t; t.hour=t.minute=t.second=0; for (i=0; i<100000; i++) /*控制时钟运行的时间*/ { update(&t); /*时钟更新*/ display(&t); /*时间显示*/ Delay(); /*模拟延时1秒*/ } } 公共计算机基础教研部