C语言程序设计第五章 复杂构造数据类型
——————————————————————————
——————————
济南大学第五章 复杂构造数据类型
5.1 结构体
5.2 共用体
5.3 枚举类型
5.4 链表
5.1 结构体在解决实际问题时,有时需要将 多个不同类型的数据 组合在一起表达一个整体的信息。
例如:描述一个学生的完整信息时,有学号、姓名、年龄、成绩、家庭地址等项。
num name sex age score addr
5001 Li Ming M 19 96.5 Beijing
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
C语言提供了这种数据结构,允许用户将不同类型的数据组合成一个有机的整体,这些数据互相联系;这种数据结构称为 结构体 (structure)。
结构体类型在使用之前应先定义,然后再定义该类型变量,
才能使用。
定义一个结构体类型的一般形式:
struct 结构体名
{
类型标识符 1 成员名 1;
类型标识符 2 成员名 2;
…… ……
类型标识符 n 成员名 n;
};
成员表列
(域表)
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
1 定义结构体类型变量的方法
1、先定义结构体类型再定义结构体变量
struct student
{ int num;
char name[20];
float score;
};
struct student stu1,stu2;
结构体类型名 变量列表在定义了结构体变量后,系统会为之分配内存单元。
sizeof(stu1)= 2 + 20 + 4 = 26
num 2B
name 20B
score 4B
num 2B
name 20B
score 4B
stu1
stu2
2、在定义结构体类型的同时定义变量
struct student
{
int num;
char name[20];
float score;
}stu1,stu2;
3、直接定义结构体类型变量
struct
{
int num;
char name[20];
float score;
}stu1,stu2;
(不出现结构体类型名)
4、说明
①、类型与变量是不同的概念,不要混淆:
只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算;在编译时,对类型不分配内存空间,只对变量分配空间。
②、结构体变量可以嵌套定义;
struct date
{
int year;
int month;
int day;
};
struct student
{ int num;
char name[20];
char sex;
struct date birth;
char addr[30];
};
sizeof(struct student)=? 2+20+1+6+30=59
2 结构体变量的引用
1、引用形式:
结构体变量名,成员名成员运算符,优先级最高
struct student
{ int num;
char name[20];
float score;
};
struct student stu1,stu2;
stu1.num=10001;
strcpy(stu1.name,"Li Ming");
stu1.score=95;
例、定义一个结构体类型 student,成员包括学号、姓名和成绩,请输入并输出该学生的信息。
问题:
如何定义一个结构体类型?
如何使用结构体类型?
定义相应的变量
结构体类型定义在何处?函数内还是函数外?
都可以,但一般放在函数外面,且放在所有函数之前,预处理命令之后,以便所有的函数都可以使用;类似全局变量
如何输入输出结构体成员?
逐个输入输出成员
#include <stdio.h>
struct student
{ int num;
char name[20];
float score;
};
void main( )
{
}
struct student s;
printf("\nnum:");
scanf("%d",&s.num);
printf("name:");
scanf("%s",s.name);
printf("score:");
scanf("%f",&s.score);
printf("\nnum:%d\n",s.num);
printf("name:%s\n",s.name);
printf("score:%f\n",s.score);
printf("\nnum:");
scanf("%d",&s.num);
getchar( );
printf("name:");
gets(s.name);
说明:在使用 gets函数前使用
getchar函数,把上次的回车读走
2、不能将一个结构体变量作为一个整体进行输入输出;
printf("%d%s%f",stu1); ×
scanf("%d%s%f",&stu1); ×
只能对结构体中的各个成员分别进行输入输出。
printf("%d%s%f",stu1.num,stu1.name,stu1.score);
scanf("%d",&stu1.num);
gets(stu1.name);
struct date
{
int year;
int month;
int day;
};
struct student
{ int num;
char name[20];
char sex;
struct date birth;
char addr[30];
}stu;
stu.birth.year=2002;
stu.birth.month=4;
stu.birth.day=19;
3、相同类型的结构体变量可以进行整体赋值
stu2=stu1;
stu2.num=stu1.num;
strcpy(stu2.name,stu1.name);
stu2.score=stu1.score;
因此,结构体类型变量可以作为函数的参数。
void fun(struct student stu); fun(stu1);
4、成员变量可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)
sum=stu1.score+stu2.score; stu1.age++;
5、可以引用结构体变量成员的地址,也可以引用结构体变量的地址
scanf("%d",&stu1.num); printf("%x",&stu1);
6、可以定义与结构体成员相同名字的变量,它们之间不会发生混乱。
struct student stu;
int age,year;

stu.age = 20;
stu.birthday.year = 1980;
……
age = 24 ;
year = 2000 ;
3 结构体变量的初始化在定义结构体变量的同时,可以进行初始化。
struct student
{ int num;
char name[20];
float score;
}stu1={15001,"宋红 ",89.5};
struct student stu2={15001,"宋红 ",89.5};
struct student stu3;
stu3={15001,"宋红 ",89.5};
这是赋值,错误
4 结构体数组结构体数组即基类型是结构体的数组,数组中的每个元素都是结构体变量。
定义结构体数组
1、先定义结构体类型,再定义结构体数组
struct student
{
int num;
char name[20];
float score;
}; struct student stu[30];
2、定义结构体类型的同时定义结构体数组
struct student
{
int num;
char name[20];
float score;
}stu[30];
3、直接定义结构体数组
struct
{
int num;
char name[20];
float score;
}stu[30];
例,有一个结构体 student,包含学号、姓名和成绩,输入 5个同学的信息,输出成绩最高者的信息。
#include <stdio.h>
struct student
{
int num;
char name[20];
int score;
};
void main( )
{
}
struct student stu[5];
int i,k;
printf("\n\nInput 5 students:");
for (i=0;i<5;i++)
{ printf("\nNo.%d:\n",i);
printf("num,");
scanf("%d",&stu[i].num); getchar( );
printf("name,");
gets(stu[i].name);
printf("score,");
scanf("%d",&stu[i].score);
}
k=0;
for (i=1;i<5;i++)
if (stu[k].score<stu[i].score)
k=i;
printf("\nNum,%d\nName,%s\nScore,%d",stu[k].num,
stu[k].name,stu[k].score);
结构体数组的初始化
struct student
{
int num;
char name[20];
float score;
}stu[3] = {{10101,"LiMing",95},
{10102,"LiuXia",89},
{10103,"Wang Min",95} };
struct student stu[ ]={{10101,"Li Ming",88},
{10102,"Zhang Jin",92},
{10103,"Wang Lin",98.5}};
5 结构体与指针结构体变量的指针就是该变量所占据的内存段的起始地址。
1、指向结构体变量指针的定义:
struct student
{ int num;
char name[20];
float score;
};
struct student stu,*p;
p=&stu;
注意:不能用指向结构体变量的指针指向该结构体变量的某个成员。
p=&stu.num; int *ip;ip=&stu.num; //正确访问结构体成员变量的三种方法:
①,stu.num,stu.name,stu.score
②,(*p).num,(*p).name,(*p).score
③,p->num,p->name,p->score
说明:
①、成员运算符 "."的优先级高于指针运算符 "*",因此采用 "(*p).成员名 " 形式时,括号不能省略 ;
②,"->"为 指向运算符,是优先级最高的运算符。
#include <stdio.h>
struct student
{ long num;
char name[20];
float score;
};
void main( )
{
struct student stu={95101,"Li Ming",89.5},*p=&stu;
}
printf("\n\nNo.,%ld\nName,%s\nScore,%g",stu.num,
stu.name,stu.score);
printf("\n\nNo.,%ld\nName,%s\nScore,%g\n",(*p).num,
(*p).name,(*p).score);
printf("\n\nNo.,%ld\nName,%s\nScore,%g\n",p->num,
p->name,p->score);
2、指向结构体数组的指针:
注意,p只能指向一个 struct student类型的数据 (某个元素的起始地址 ),不能指向一个成员变量。
指向结构体变量的指针变量,可以指向结构体变量,也可以指向同类型的结构体数组的元素。
struct student
{ int num;
char name[30];
float score;
}stu[30],*p;
p=stu; //正确,p→stu[0]
p=&stu[3]; //正确,p→stu[3]
p=&stu[2].num; //错误结构体数组程序举例有 30名学生,每个学生的信息包括:学号、姓名、成绩,输入学生信息,按成绩从高到低排序,并输出排序后的结果。
#include <stdio.h>
#define M 30
struct student
{
int no;
char name[10];
int score;
};
void main( )
{
struct student stu[M],temp;
int i,j,k;
printf("\n\nInput %d students:\n",M);
for (i=0;i<M;i++)
{ printf("\n The %dth student:",i+1);
printf(" No.:");
scanf("%d",&stu[i].no);
printf(" Name,");
scanf("%s",stu[i].name);
printf(" Score,");
scanf("%d",&stu[i].score);
}
for (i=0; i<M-1; i++) /* 选择法排序 */
{ k=i;
for (j=i+1; j<M; j++)
if (stu[j].score<stu[k].score)
k=j;
temp=stu[i]; stu[i]=stu[k]; stu[k]=temp; /* stu[i]←→stu[k] */
}
printf("\n\n The sorted students:\n");
printf(" %-6s%-10s%-10s\n","No.","Name","Score"); /* 输出表头 */
for (i=0;i<M;i++) /* 输出排序后的结果 */
printf(" %-6d%-10s%-10d\n",stu[i].no,stu[i].name,stu[i].score);
}
题目同上,用函数实现上述功能。用 input函数输入学生的信息,
用 sort函数按成绩从低到高排序,用 print函数输出排序后的结果。
在 main函数中调用上述函数。
#include <stdio.h>
#define M 30
struct student
{
int no;
char name[10];
int score;
};
void input(struct student s[ ],int n) /* 输入 n个学生的信息 */
{
int i;
printf("\n\n Input %d students:\n",n);
for (i=0;i<n;i++)
{ printf("\n The %dth student:\n",i+1);
printf(" No.,");
scanf("%d",&s[i].no);
printf(" Name,");
scanf("%s",s[i].name);
printf(" Score,");
scanf("%d",&s[i].score);
}
}
void sort(struct student stu[ ],int n) /* 排序 */
{
int i,j,k;
struct student temp;
for (i=0; i<n-1; i++) /* 选择法排序 */
{ k=i;
for (j=i+1; j<n; j++)
if (stu[j].score<stu[k].score)
k=j;
temp=stu[i]; stu[i]=stu[k]; stu[k]=temp; /* stu[i]←→stu[k] */
}
}
void print(struct student stu[ ],int n) /* 输出 n个学生的信息 */
{
int i;
printf(" %-6s%-10s%-10s\n","No.","Name","Score");
for (i=0;i<n;i++) /* 输出排序后的结果 */
printf(" %-6d%-10s%-10d\n",stu[i].no,stu[i].name,stu[i].score);
}
void main( )
{
struct student stu[M];
int i,j,k;
input(stu,M);
printf("\n\n The unsorted students:\n");
print(stu,M);
sort(stu,M);
printf("\n\n The sorted students:\n");
print(stu,M);
}
5.2 共用体所谓,共用体 (union)”是指使几个不同的变量共占同一段内存的数据类型。
2001
2002
2003
2004
ch i
f
把一个 char型变量、一个 int型变量、
一个 float型变量放在同一个地址开始的内存单元中。即使几个不同的变量共占同一段内存空间。
1 共用体变量的定义
1、先定义共用体类型标识符,再定义变量
union 共用体类型标识符
{
类型标识符 1 成员名 1;
类型标识符 2 成员名 2;
…… ……
类型标识符 n 成员名 n;
};
union data
{
int i;
char ch;
float f;
};
union 共用体类型标识符 变量名表; union data a,b,c;
2,直接定义共用体变量
union 共用体类型标识符
{
类型标识符 1 成员名 1;
类型标识符 2 成员名 2;
…… ……
类型标识符 n 成员名 n;
}变量名表 ;
union data
{ int i;
char ch;
float f;
}a,b,c;
union
{ int i;
char ch;
float f;
}a,b,c;
3,共用体与结构体的定义形式相似,但含义不同:
结构体变量所占的内存长度等于各成员所占的内存长度之和。 (每个成员分别占有自己的内存 )
共用体变量所占的内存长度等于最长的成员的长度。 (每个成员占用相同的内存 )
sizeof(union data)= 4
1、引用形式为,共用体变量名,成员名
union data
{ int i;
char ch;
float f;
}a,b,c;
a.i 引用共用体变量 a中的整型变量 i
a.ch 引用共用体变量 a中的字符变量 ch
a.f 引用共用体变量 a中的实型变量 f
2、注意:
不能直接引用共用体变量,而只能引用共用体变量的成员
printf("%d",a);
printf("%d",a.i); printf("%c",a.ch);
3、共用体类型数据的特点:
①,同一内存段可以用来存放几种不同类型的成员,但在某一时刻只能存放其中一种,而不是同时存放几种;
2 共用体变量的引用
②,共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员就失去作用;
a.i=1; a.ch='a'; a.f=1.5;
③,共用体变量的地址和它的各成员的地址是同一地址 ;
&a,&a.i,&a.ch,&a.f都是同一地址
④,不能对共用体变量名赋值 ; 也不能企图引用变量名来得到成员的值 ; 不能在定义共用体变量时进行初始化 ;
a=1; b=a;
union
{ int i;
char ch;
float f;
}a={1,'a',1.5};
⑤,不能把共用体变量作为函数参数,也不能让函数带回共用体变量,但 可以使用指向共用体变量的指针 ;
⑥,共用体作为一种数据类型,可以在定义其它数据类型中使用。
可以将结构体变量的某一成员定义为共用体类型,也可以定义共用体数组。
例,设有若干人员的数据,其中有学生和教师。
学生的数据包括:姓名、学号、性别、职业、班级。
教师的数据包括:姓名、教师号、性别、职业、职务。
现要求把它们放在同一表格中。
name num sex job class position
Li 10101 M s 501
Wang 5002 F t prof
int num;
char name[20];
char sex;
char job;
union
{ int class;
char position[10];
}category;
name num sex job class position
Li 10101 M s 501
Wang 5002 F t prof
struct person
{ int num;
char name[20];
char sex;
char job;
union
{ int class;
char position[10];
}category;
}per[30];
scanf("%c",&per[i].job);
if (per[i].job=='s')
scanf("%d",&per[i].category.class);
else if (per[i].job=='t')
gets(per[i].category.position);
5.3 枚举类型所谓,枚举,是指将变量的所有取值一一列举出来,变量的值只限于列举出来的值的范围内。
枚举类型变量的定义:
1,先定义枚举类型标识符,再定义变量
enum 枚举类型标识符 {枚举元素 1,枚举元素 2,……,枚举元素 n};
enum 枚举类型标识符 变量列表 ;
enum person{Man,Woman};
enum person wang;
enum weekday{Sun,Mon,Tue,Wed,Thu,Fri,Sat};
enum weekday workday,weekend;
2,直接定义枚举变量
enum 枚举类型标识符 {枚举元素 1,枚举元素 2,……,
枚举元素 n}变量列表 ;
enum person{Man,Woman}wang;
enum weekday{Sun,Mon,Tue,Wed,Thu,Fri,Sat}workday,weekend;
enum BOOL{FALSE,TRUE};
3,说明:
Sun,Mon,……,Sat等称为 枚举元素 或 枚举常量 。
枚举变量的引用
1、在C编译时,对枚举元素按常量处理,故称 枚举常量 。它们不是变量,不能对它们赋值 。
Sun=0; //错误 TRUE=1; //错误
2、枚举元素作为常量,它们是有值的。 C语言编译时按定义时的顺序使它们的值为 0,1,2,……
enum weekday{Sun,Mon,Tue,Wed,Thu,Fri,Sat}workday;
workday=Mon; printf("%d\n",workday);
3、可以在定义时改变枚举元素的值
enum weekday{Sun=7,Mon=1,Tue,Wed,Thu,Fri,Sat}workday;
enum weekday{Sun=7,Mon,Tue,Wed=0,Thu,Fri,Sat};
4、枚举值可以用来做判断比较
if (workday==Mon)
……
if (workday>Sun)
……
5、一个整数不能直接赋给一个枚举变量
workday=2; //错误
T h e E n d