940 likes | 1.04k Views
第 7 章 结构体与共用体. 7.1 结构体类型与结构体变量 7.2 结构体数组 7.3 结构体与函数 7.4 动态数据结构 7.5 共用体 7.6 案例应用. 7.1 结构体类型与结构变量. 用户自定义数据类型 —— 结构体 结构体 是在一个名称之下的多个数据的集合。构成结构体的每个数据称为 成员 (member) ,也可称为 元素 (element) 或 域 (field) ; 和数组不一样的是,这些 成员各有自己的名字,类型也可以各不相同。 数组一般用于处理多个对象的同一属性,而结构体一般用于表示一个对象的多个不同属性。.
E N D
第7章 结构体与共用体 7.1 结构体类型与结构体变量 7.2 结构体数组 7.3 结构体与函数 7.4 动态数据结构 7.5 共用体 7.6 案例应用
7.1 结构体类型与结构变量 • 用户自定义数据类型——结构体 • 结构体是在一个名称之下的多个数据的集合。构成结构体的每个数据称为成员(member),也可称为元素(element)或域(field); • 和数组不一样的是,这些成员各有自己的名字,类型也可以各不相同。数组一般用于处理多个对象的同一属性,而结构体一般用于表示一个对象的多个不同属性。
7.1.1 结构体类型的定义 • 结构体类型定义的语法形式茹下: struct结构体标识符 { 成员变量列表; }; 遵循C语言标识符命名规则 可以是基本数据类型、数组和指针类型,也可以是结构体。 成员不能重名。 不能省略
7.1.1 结构体类型的定义 结构体名 例:为了描述班级,可以定义如下的结构体: struct Class { char code[10]; /*编号 */ char major[30]; /*专业*/ unsigned int count; /*人数*/ }; 例:描述学生,可以定义: struct student { long number; char name[10]; char sex; short age; double C; double M; double E; }; 成员类型名 成员名 不能省略
7.1.2 结构体变量的定义与初始化 • 定义结构体类型变量有三种方法: 1.定义结构体类型后定义变量 在上面定义了一个结构体类型 struct student 之后,可以用它定义变量,以便存储一个具体的学生,例如: struct student stud; 系统给stud变量分配45个字节的内存空间。 结构体类型名 结构体变量名
7.1.2 结构体变量的定义与初始化 2.定义结构体类型同时定义变量 struct结构体标识符 { 成员变量列表; }变量1,…,变量n; 例: struct student { long number; char name[10]; char sex; short age; double C; double M; double E; }stud1,stud2;
7.1.2 结构体变量的定义与初始化 例: struct { long number; char name[10]; char sex; short age; double C; double M; double E; }stud1,stud2; 3.直接定义变量 此种方法在定义结构体的同时定义结构体类型的变量,但是不给出结构体标识符。 struct { 成员变量列表; }变量1,…,变量n;
7.1.2 结构体变量的定义与初始化 • 关于结构体类型,有几点说明: (1) 类型和变量是不同的概念,如以上定义的struct student是结构体类型名,它与int、char等一样是类型名。只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。编译时,对类型不分配内存空间,只对变量分配内存空间。
7.1.2 结构体变量的定义与初始化 (2) 成员也可以是其他结构体类型的变量。 struct date { int month;int day; int year;}; struct student { long number; char name[10]; char sex; struct datebirthday; int score[3]; }stud1,stud2;
7.1.2 结构体变量的定义与初始化 (2) 成员可以属于另一个结构体类型。 (3)结构体中的成员可以和程序中的变量同名,但二者不表示同一对象。例如程序中可以定义一个变量name,它与struct student中name成员是不同的,互不干扰。
7.1.2 结构体变量的定义与初始化 (4)结构体类型并非只有一种,而是可以设计出许多种结构体类型,例如 struct teacher struct worker struct date等结构体类型 各自包含不同的成员
7.1.2 结构体变量的定义与初始化 • 结构体变量的初始化 struct结构体标识符 变量名={初始化值1, 初始化值2,…, 初始化值n }; 例: struct person { char name[20]; char sex; int age; float height; }per={“Li Ming”,‘M’,20,172.5}; 每个常量表达式类型应与对应结构成员的类型一致。
7.1.2 结构体变量的定义与初始化 在初始化结构体变量时候,既可以初始化其全部成员变量,也可以仅仅对其中部分的成员变量进行初始化。例: struct Student { long id; char name[20]; char sex; }a= {0}; 相当于a.id=0;a.name=“”;a.sex=‘\0x0’。
7.1.3 结构体变量的引用 1.对结构体变量中成员的引用 通过成员运算符“.”可以存取结构中的成员,结构体成员的引用形式如下: 结构全变量名.成员名; 例如: stud1.number=20101101L; strcpy(stud1.name,”li ming”); stud1.sex=’m’; stud1.birthday.year=1992; 成员运算符,优先级别第1级
#include <stdio.h> struct date { int month; int day; int year; }; struct student { long number; char name[10]; char sex; struct date birthday; int score[3]; }; void main() { struct student stud; stud.number=20101101L;
printf(“please input name:”); gets(stud.name); stud.sex=’m’; stud.birthday.year=1992; stud.birthday.year++; stud.birthday.month=8; stud.birthday.day=12; printf(“please input score:”); scanf(“%d%d%d”,&stud.score[0], &stud.score[1],&stud.score[2]); printf(“%ld%s%4c\n”,stud.number, stud.name,stud.sex); printf(“birthday:%d-%d-%d\n”, stud.birthday.month,stud.birthday.day, stud.birthday.year); printf(“score;%d,%d,%d”,stud.score[0], stud.score[1],stud.score[2]); } 连续用两个’.’引用 最低一级成员
7.1.3 结构体变量的引用 2.对整个结构体变量的引用 (1)相同类型的结构体变量可以相互赋值。 例如:struct student stud1,stud2; stud1=stud2; //合法的赋值表达式,将stud2的全部内容赋给stud1,而不必逐个成员地多次赋值。 (2)结构体变量可以取地址。 例如:struct student stud; &stud;//是合法的表达式,结果是结构体变量stud的地址。
7.1.3 结构体变量的引用 (3)不能将一个结构体变量作为一个整体进行输入输出。 例如:struct { int x; int y; }a; a.x=4; a.y=5; printf(“%d,%d\n”,a); //引用是错误的 只能对结构体变量的各个成员分别进行输入输出。对结构体成员的操作和同类型变量的操作相同。
【例7.2】输入3个同学的姓名、数学成绩、英语成绩和物理成绩,确定总分最高的同学,并打印其姓名及其三门课程的成绩。【例7.2】输入3个同学的姓名、数学成绩、英语成绩和物理成绩,确定总分最高的同学,并打印其姓名及其三门课程的成绩。 #include <stdio.h> #include <string.h> struct student { char Name[20]; /*姓名*/ float Math; /*数学*/ float English; /*英语*/ float Physical; /*物理*/ };
void main() { struct Student oStu; struct Student oMaxStu; int i; float fMaxScore; float fTotal; printf("\nPlease input 3 students and there score\n"); printf("----------------------------------------\n"); printf("Name Math English Physical \n"); printf("----------------------------------------\n"); fMaxScore=0;
for(i=0;i<3;i++) { scanf("%s %f %f %f",oStu.Name, &oStu.Math,&oStu.English,&oStu.Physical); fTotal=oStu.Math+oStu.English+oStu.Physical; if(fMaxScore<fTotal) { fMaxScore=fTotal; strcpy(oMaxStu.Name,oStu.Name); oMaxStu.Math=oStu.Math; oMaxStu.English=oStu.English; oMaxStu.Physical=oStu.Physical; } } printf("----------------------------------------\n"); printf("%s %6.2f %6.2f %6.2f\n",oMaxStu.Name, oMaxStu.Math,oMaxStu.English,oMaxStu.Physical); }
7.1.4 指向结构体变量的指针 1.结构体指针变量的定义 形式2: struct 结构体标识符 { 成员变量列表; } *指针变量名; 形式3: struct { 成员变量列表; }*指针变量名; 形式1: struct 结构体标识符 { 成员变量列表; }; struct 结构体标识符 *指针变量名;
7.1.4 指向结构体变量的指针 1.结构体指针变量的定义 例: struct time { int hour; int minute; int second; }; struct time *pt; 或: struct time { int hour; int minute; int second; }*pt; struct date worktime; pt=&worktime;
7.1.4 指向结构体变量的指针 2.结构体指针变量的初始化 例: struct Point oPoint={0,0,0}; struct Point pPoints=&oPoint; 或: struct Point oPoint={0,0,0}; struct Point *pPoints2; pPoints2=&oPoint;
7.1.4 指向结构体变量的指针 3.通过结构体的指针引用结构体的成员 例: struct time worktime,*p=&wortime; 则通过结构体的指针引用结构体成员的形式如下: (*p).hour /*等同于worktime.hour*/ (*p).minute /*等同于worktime.minute*/ (*p).second /*等同于worktime.second*/ (*p).hour 不等同于 *p.hour (1)使用间接访问运算符“*”引用结构体成员 基本引用形式是: (*结构体的指针).成员名 等同*(p.hour) ×
7.1.4 指向结构体变量的指针 例: struct time d,*p=&d; 则以下同一行的三个表达式是等价的。 p->time (*p).time d.time p->minute (*p).minute d.minute p->second (*p).second d.second 成员选择运算符“->”的优先级别和结合性与“.”相同,处于第1级。 (2)使用成员选择运算符“->” 也称为箭头操作符,基本引用形式是: 结构体的指针->成员名
7.1.4 指向结构体变量的指针 struct { int num; char *name; }s={1,”abcdefg”},*p=&s; 表达式 结果 说明 p->num++ 1先访问s.num,再把s.num加1 ++p->num2 s.num加1值变为2,后访问s.num p->name s.name表示字符串”abcdefg” *p->name‘a’访问s.name指向的对象,即字符’a’ *p->name++‘a’访问s.name指向的对象即字符’a’, 然后使p->name即s.name指向下一个字符’b’ (*p->name)++‘a’先访问p->name指向的对象即字 符’a’,然后使(*p->name)加1
#include <stdio.h> void main() { struct { int x; int y; }a[2]={{1,2},{3,4}},*p=a; printf(“%d,”,++p->x); printf(“%d\n”,(++p)->x); } a[0].x= 1 ; a[0].y=2; a[1].x= 3 ; a[1].y=4; 2 等价于:++(p->x) 运行结果: 2,3
#include <stdio.h> struct Point { double x; /*x坐标*/ double y; /*y坐标*/ double z; /*z坐标*/ }; void main() { struct Point oPoint1={100,100,0}; struct Point oPoint2; struct Point *pPoint; pPoint=&oPoint2; (*pPoint).x= oPoint1.x; (*pPoint).y= oPoint1.y; (*pPoint).z= oPoint1.z; printf("oPoint2={%7.2f,%7.2f,%7.2f}", oPoint2.x, oPoint2.y, oPoint2.z); } 结果:oPoint2={ 100.00, 100.00, 0.00}
7.1.5 关键字typedef的用法 • 可以使用typedef命令给已有的数据类型起“别名”,用来代替原有的数据类型名。 例如: typedef int INTERGER; 定义的INTERGER等价于数据类型名int,可以用INTERGER定义变量。 INTERGER i,j; 变量i、j为INTERGER类型,也就是int类型的变量。 又如: typedef char ADDRESS[20]; 声明char [20]类型的别名是ADDRESS,用它来定义变量: ADDRESS s1,s2; 变量s1和s2定义成为ADDRESS类型的即char [20]类型的,为20个字符组成的数组。 char s1[20],s2[20];
7.1.5 关键字typedef的用法 • typedef的一般使用形式如下: typedef原类型名 新类型名; 例如: typedef struct { int year; int month; int day; }DATE; 定义类型名DATE,它表示上面指定的结构体类型。 DATEbirthday;
7.1.5 关键字typedef的用法 例如: typedef int SCORE[20]; //定义新类型SCORE,它表示20个整数组成的一维数组类型。 typedef char *STRING; //定义新类型名,它表示字符指针类型。 typedef DATE *DATE_P 这里采用了typedef的嵌套定义,定义的类型DATE_P为指向DATE结构类型的指针。 STRINGp; 等价于:char *p;
7.1.5 关键字typedef的用法 在使用typedef时,应当注意如下的问题: (1)typedef的目的是为已知数据类型增加一个新的名称。因此并没有引入新的数据类型。 (2)typedef 只适于类型名称定义,不适合变量的定义。 (3)typedef 与#define具有相似的之处,但是实质不同。 #define AREA double与 typedef double AREA可以达到相同的效果,但是其实质不同。#define为预处理命令,typedef是为已知数据类型增加一个新名称。
7.2 结构体数组 7.2.1 结构体数组的定义 形式2: struct 结构体标识符 { 成员变量列表; }数组名[数组长度]; 形式3: struct { 成员变量列表; }数组名[数组长度]; 形式1: struct 结构体标识符 { 成员变量列表; }; struct 结构体标识符 数组名[数组长度];
7.2.1 结构体数组的定义 例:定义一个可以存放3个学生数据的结构体数组。 struct student { long number; char name[20]; char sex; int age; float height; }s[3]; S[0] s[1] s[2]
7.2.1 结构体数组的定义 1.数组元素的引用 数组元素引用的语法形式如下: 数组名[数组下标]; 2.数组的引用 (1)作为一块连续存储单元的起始地址与结构体指针变量配合使用; (2)作为函数参数。
7.2.1 结构体数组的定义 引用结构体数组的元素和引用普通数组元素一样,例如s[0],它是一个结构体类型变量,因此可以象对普通结构体类型变量一样对它进行相应操作,如可以引用s[0]的成员。 例如: s[0].number取值为10101 s[0].name取值为”zhangsan” s[0].sex取值为’M’ s[0].age取值为19 s[0].score取值为93 对s[1]的各个成员赋值: s[1].number=10104; gets(s[1].name); s[1].sex=’F’; s[1].age=20; s[1].score=85;
7.2.2 结构体数组的初始化 在定义数组的同时,对其中的每一个元素进行初始化。例如: struct student { long number; char name[20]; char sex; int age; float height; }s[3]={{10101, “zhangsan”,’M’,19,177}, {10104, “liming”,’F’,20,164.5}, {10106, “wangwu”’M’,18,175.5}};
7.2.2 结构体数组的初始化 在定义数组并同时进行初始化的情况下,可以省略数组的长度,系统根据初始化数据的多少来确定数组的长度。例如: struct Key { char word[20]; int count; }keytab[]={{“break”,0}, {“case”,0},{“void”,0}}; 结构体数组keytab的长度,系统自动确认为3。
7.2.3 结构体数组的应用 【例7.5】编程,输入5个学生的姓名和数学、英语和语文三门功课的成绩,计算每个学生的平均成绩,并输出学生姓名和平均成绩。 分析: 程序中定义一个结构体数组s,它有5个数组元素,用于存放5个学生数据。每个数组元素是struct student结构体类型变量,包含5个成员:name(姓名)、math(数学成绩)、eng(英语成绩)、cuit(语文成绩)、aver(平均成绩)。
#include <stdio.h> #define N 5 struct student { char name[20];/*学生姓名*/ float math;/*数学成绩*/ float eng;/*英语成绩*/ float cuit;/*语文成绩*/ float aver;/*平均成绩*/ };
void main() { struct student s[N]; int i; for(i=0;i<N;i++) { printf(“请输入第%d学生的数据\n”,i+1); printf(“姓名:”); scanf("%s",s[i].name); printf(“数学、英语、语文成绩:”); scanf(“%f %f %f”, &s[i].math,&s[i].eng,&s[i].cuit); s[i].aver=(s[i].math+s[i].eng+s[i].cuit)/3.0; } printf(“姓名 平均成绩\n”); for(i=0;i<N;i++) printf(“%s %10.1f\n”,s[i].name,s[i].aver); }
7.2.3 结构体数组的应用 【例7.6】输入N个整数,记录输入的数和序号,按从小到大的顺序排列(如果两个整数相同,按输入的先后次序排列)。输出排序以后的每个整数和它原来的序号。 分析: 采用结构体类型struct data来表示每个整数,有成员no(序号)和num(整数)。 程序中定义一个由N个 struct data类型的数组元素的结构体数组x,首先输入所有整数,并记录每个整数的输入序号;输入完成后,采用冒泡排序法对该数组进行排序。
#include <stdio.h> #define N 10 struct data { int no; int num; }; void main() { struct data x[N],temp; int i,j; printf("输入10个整数:"); for(i=0;i<N;i++) { scanf("%d",&x[i].num); x[i].no=i+1; }
for(i=0;i<N-1;i++) for(j=0;j<N-i-1;j++) if (x[j+1].num<x[j].num) { temp=x[j]; x[j]=x[j+1]; x[j+1]=temp; } printf("值 原来序号\n"); for(i=0;i<N;i++) printf("%5d %5d\n",x[i].num,x[i].no); }
7.3 结构体与函数 结构体也可作为函数的参数,有三种形式: • 结构体变量的成员作函数的参数。与普通变量作函数参数一样,是将结构体变量的成员的值单向传递给形参。 • 结构体变量作函数的参数。结构体变量作函数的参数是将结构体变量的所有成员的值逐个传递给同结构类型形参,也属单向值传递。 • 用指向结构体变量的指针作函数的参数。是将结构体变量的地址传递给形参,此时形参和实参共用内存空间,形参值的改变等价于对应实参值的改变,因此它属于双向传递。
【例7.7】结构体变量作为函数参数,计算职工的实发工资。【例7.7】结构体变量作为函数参数,计算职工的实发工资。 #include<stdio.h> struct employee { int num; char name[20]; float jbgz, jj, bx, sfgz; }; float count_sfgz(struct employee m); void main() { int i,n; struct employee e; printf("请输入职工人数n:"); scanf("%d",&n);
for(i=1;i<=n;i++) { printf("请输入第%d个职工的信息:",i); scanf("%d%s", &e.num, e.name); scanf("%f%f%f", &e.jbgz, &e.jj, &e.bx); e.sfgz= count_sfgz(e); printf("编号:%d 姓名:%s 实发工资:%.2f\n", e.num, e.name, e.sfgz); } } float count_sfgz(struct employee m) { return m.jbgz+ m.jj-m.bx; }
【例7.8】结构体指针作为函数参数,设置学生成绩等级并统计不及格人数。【例7.8】结构体指针作为函数参数,设置学生成绩等级并统计不及格人数。 #include<stdio.h> #define N 5 struct student { int num; char name[20]; int score; char grade; }; int set_grade(struct student *p); void main() { struct student stu[N], *ptr; int i, count; ptr = stu;
printf("Input the student's number, name and score: \n"); for(i = 0; i < N; i++) { printf("No %d: ", i+1); scanf("%d%s%d", &stu[i].num, stu[i].name, &stu[i].score); } count = set_grade(ptr); printf("The count (<60): %d\n", count); printf("The student grade:\n"); for(i = 0; i < N; i++) printf("%d %s %c\n", stu[i].num, stu[i].name, stu[i].grade); }