白 雪 飞
baixf@ustc.edu.cn
中国科学技术大学电子科学与技术系
Dept,of Elec,Sci,& Tech.,USTC
Fall,2003
第 8章 结 构 体
C语言程序设计 - 第 8章 结构体 2
目 录
? 结构体
? 结构体数组
? 指向结构体的指针
? 定义类型别名
? 动态存储分配函数
? 结构体的应用 — 链表
C语言程序设计 - 第 8章 结构体 3
结构体 (Structure)
? 结构体概述
? 结构体类型的声明
? 结构体变量的定义
? 结构体变量的初始化
? 结构体变量的引用
C语言程序设计 - 第 8章 结构体 4
结构体概述
? 结构体
?将不同类型的数据组合成一个整体
?用来表示简单类型无法描述的复杂对象
?可以用结构体来定义用户自己的数据结构
? 举例
?描述学生信息
num name sex age score addr
12039 Bill Gates M 40 76.5 New York
C语言程序设计 - 第 8章 结构体 5
结构体类型的声明
? 一般形式
?struct [结构体名 ] {
成员表列
};
?“成员表列” 形式
类型 成员名 ;
类型 成员名 ;
...,..
C语言程序设计 - 第 8章 结构体 6
结构体类型声明的说明 (1)
? 声明了一种类型,而不是定义变量
? 结构体名可以没有,但是这样就无法再
次使用该结构体类型了
? 成员表列中是成员 (Member)的定义
? 成员的定义形式与变量定义相同
? 成员类型可以是另一结构体类型,但不
可直接或间接递归嵌套
? 成员表列不可为空,至少要有一个成员
C语言程序设计 - 第 8章 结构体 7
结构体类型声明的说明 (2)
? 注意 {}不表示复合语句,其后有分号
? 同一结构体的成员不能重名
? 不同结构体的成员可以重名
? 结构体成员和其他变量可以重名
? 结构体类型与其成员或其他变量可重名
?struct test { int test; } test;
? 结构体类型名称是 struct 结构体名,
注意 struct关键字不能省略
C语言程序设计 - 第 8章 结构体 8
结构体类型声明的说明 (3)
? 即使两个结构体声明中的成员类型、名
称、顺序都完全一致,它们也是不同的
类型
? 结构体类型也要“先声明,后使用”
? 如果结构体类型声明在函数内部,则该
函数之外无法引用此结构体类型
? 一般把结构体类型声明放到文件最前面
? 也可以把结构体类型声明放在头文件里
C语言程序设计 - 第 8章 结构体 9
结构体类型的声明举例
struct student {
unsigned num; /* 学号 */
char name[20]; /* 姓名 */
char sex; /* 性别 */
unsigned age; /* 年龄 */
float score; /* 分数 */
char addr[50]; /* 地址 */
};
C语言程序设计 - 第 8章 结构体 10
结构体变量的定义 (1)
? 先声明结构体类型再定义变量
struct student {
unsigned num;
char name[20];
char sex;
unsigned age;
float score;
char addr[50];
};
struct student stu1,stu2;
C语言程序设计 - 第 8章 结构体 11
结构体变量的定义 (2)
? 在声明结构体类型的同时定义变量
struct student {
unsigned num;
char name[20];
char sex;
unsigned age;
float score;
char addr[50];
} stu1,stu2;
C语言程序设计 - 第 8章 结构体 12
结构体变量的定义 (3)
? 直接定义无名结构类型变量
struct {
unsigned num;
char name[20];
char sex;
unsigned age;
float score;
char addr[50];
} stu1,stu2;
C语言程序设计 - 第 8章 结构体 13
结构体声明和变量定义举例
struct date {
int year,month,day;
};
struct student{
unsigned num;
char name[20];
char sex;
struct date birthday;
float score;
} stu1,stu2;
C语言程序设计 - 第 8章 结构体 14
结构体变量的初始化
? 按照成员的顺序和类型对成员初始化
struct date date1 = {1984,10,20};
struct student stu = {
1001,/*unsigned num*/
"Tom",/*char name[20]*/
'M',/*char sex*/
{1983,9,20},/*struct date birthday*/
93.5 /*float score*/
};
C语言程序设计 - 第 8章 结构体 15
结构体变量中成员的引用
? 一般形式
?结构体变量名,成员名
? 成员运算符,
?具有最高的优先级,自左向右结合
? 说明
?结构体成员和同类型的变量用法相同
?若成员类型又是一个结构体,则可以使用若
干个成员运算符,访问最低一级的成员
C语言程序设计 - 第 8章 结构体 16
结构体变量中成员的引用举例
struct student stu;
...,..
scanf("%f",&stu.score);
stu.num = 12345;
stu.birthday.month = 11;
stu.score = sqrt(stu.score) * 10;
strcpy(stu.name,"Mike");
printf("No.%d:",stu.num);
C语言程序设计 - 第 8章 结构体 17
结构体变量整体引用
? 结构体类型变量之间可以直接相互赋值
?实质上是两个结构体变量相应的存储空间中
的所有数据直接拷贝
?包括复杂类型在内的所有结构体成员都被直
接赋值,如字符串、结构体类型等
? 函数的实参和形参可以是结构体类型,
并且遵循实参到形参的单向值传递规则
? 为了提高程序的效率,函数的参数多使
用结构体类型指针
C语言程序设计 - 第 8章 结构体 18
结构体变量整体引用举例
struct student stu1,stu2={1002,"Kate",'F',
{1981,11,4},89.0};
void print(struct student s)
{
printf("%d,%4s,%c,%d.%02d.%02d,%4.1f\n",
s.num,s.name,s.sex,s.birthday.year,
s.birthday.month,s.birthday.day,s.score);
}
void main ()
{
stu1 = stu2; /* 直接赋值 */
print(stu1); /* 1002,Kate,F,1981.11.04,89.0 */
}
C语言程序设计 - 第 8章 结构体 19
结构体数组
? 结构体数组的用法与基本类型数组类似
?定义、初始化、引用等
? 结构体数组可用于表示二维表格
? 举例
struct student s[10];
for (i=0; i<10; i++)
scanf("%d,%s,%c,%d,%f",
&s[i].num,s[i].name,&s[i].sex,
&s[i].age,&s[i].score);
C语言程序设计 - 第 8章 结构体 20
结构体数组初始化及应用举例
struct student stu[] = {
{1001,"Tom",'M',{1980,1,2},85.5},
{1002,"Kate",'F',{1981,11,4},89.0},
{1003,"Mike",'M',{1980,3,5},95.5}};
for (i=0; i<3; i++)
printf("%d,%4s,%c,%d.%02d.%02d,%4.1f\n",
stu[i].num,stu[i].name,
stu[i].sex,stu[i].birthday.year,
stu[i].birthday.month,
stu[i].birthday.day,stu[i].score);
C语言程序设计 - 第 8章 结构体 21
结构体数组与二维表
num name sex birthday scoreyear month day
s[0] 1001 Tom M 1980 1 2 85.5
s[1] 1002 Kate F 1981 11 4 89.0
s[2] 1003 Mike M 1980 3 5 95.5
s[3] 1004 John M 1981 8 13 73.0
s[4] 1005 Lily F 1981 3 6 81.0
struct student s[5]; 结构体




C语言程序设计 - 第 8章 结构体 22
指向结构体的指针
? 指向结构体的指针
?定义、使用与其他基本类型指针类似
?可以使用指向运算符 (->)引用指针所指向的
结构体的成员
? 指向运算符 ->
?结构体指针 ->成员名
?具有最高的优先级,自左向右结合
?若 struct student stu,*p=&stu;
则 stu.num,(*p).num,p->num等效
C语言程序设计 - 第 8章 结构体 23
指向结构体数组的指针
? 指向结构体数组的指针
?与指向其他基本类型数组的指针用法类似
?注意相关运算符的结合方向和优先级
? 举例
struct student stu[10],p=stu;
++p->num; /* 同 ++(p->num); */
p++->num; /* 同 (p++)->num; */
(++p)->num;
(p++)->num;
C语言程序设计 - 第 8章 结构体 24
结构体指针作函数参数举例
void input(struct student *p)
{
scanf("%d %s %c %d.%d.%d %f",
&p->num,p->name,&p->sex,
&p->birthday.year,&p->birthday.month,
&p->birthday.day,&p->score);
}
void main ()
{
struct student stu[20];
int i;
for (i=0; i<20; i++) input(stu+i);
}
C语言程序设计 - 第 8章 结构体 25
定义类型别名
? 一般形式
?typedef <变量定义形式中变量名换成类型名 >
? 举例
?typedef float REAL;
?typedef struct {
int month;
int day;
int year;
} DATE;
C语言程序设计 - 第 8章 结构体 26
动态存储分配函数
? 动态分配存储
?根据需要开辟或释放存储单元
? 相关函数
?malloc函数
?calloc函数
?free函数
? 说明
?应包含 malloc.h或 stdlib.h
C语言程序设计 - 第 8章 结构体 27
malloc函数
? 函数原型
?typedef unsigned size_t;
?void *malloc(size_t size);
? 参数
?size:分配存储空间的字节数
? 返回值
?若成功,返回指向分配区域起始地址的指针
?若失败,返回 NULL
C语言程序设计 - 第 8章 结构体 28
calloc函数
? 函数原型
?void *calloc(size_t n,
size_t size);
? 参数
?n,分配内存的项目数
?size:分配 内存的 每个项目的字节数
? 返回值
?若成功,返回指向分配区域起始地址的指针
?若失败,返回 NULL
C语言程序设计 - 第 8章 结构体 29
free函数
? 函数原型
?void free(void *ptr);
? 参数
?ptr:要释放的内存区地址
? 说明
?释放 prt指向的内存区
?释放后的内存区能够分配给其他变量使用
C语言程序设计 - 第 8章 结构体 30
结构体的应用 — 链表 (Link List)
a1 a2 a3,.,an ^head
struct node
data next
ai
struct node {
int data;
struct node *next;
};
struct node *head;
C语言程序设计 - 第 8章 结构体 31
链表的操作
? 链表的建立
?从链尾到链头:新结点插入到链头
?从链头到链尾:新结点插入到链尾
? 链表的遍历
? 删除结点
?根据一定的条件,删除一个或多个结点
? 插入结点
?根据一定的条件,把新结点插入到指定位置
C语言程序设计 - 第 8章 结构体 32
建立链表 (从链尾到链头 )
head ai-1,..
④ head = p;
② p = malloc(sizeof (struct node));
p->data = a[i];
① for(i=0; i<n; i++)
p
ai ③ p->next = head;
C语言程序设计 - 第 8章 结构体 33
建立链表 (从链头到链尾 )
ai-1 ^...
④ p->next = q;
② q = malloc(sizeof (struct node));
q->data = a[i];
① for(i=0; i<n; i++)
ai ^
q ③ q->next = NULL;
p ⑤ p = q;
C语言程序设计 - 第 8章 结构体 34
遍历链表
..,ai-1 ai ai+1,..
③ p = p->next;
p
① while(p)
② printf("%d",p->data);
C语言程序设计 - 第 8章 结构体 35
删除结点
..,ai-1 ai ai+1,..
③ p->next = q->next;
④ free(q);
② q = p->next;
p q
① if(p->next满足删除条件 )
C语言程序设计 - 第 8章 结构体 36
插入结点
..,ai ai+1,..
④ p->next = q;
② q = malloc(sizeof (struct node));
q->data = x;
p ① if(p满足插入条件 )
q
x
③ q->next = p->next;
C语言程序设计 - 第 8章 结构体 37
链表操作中需要注意的几个问题
? 注意考虑几个特殊情况下的操作
?链表为空表 (head==NULL)
?链表只有一个结点
?对链表的第一个结点进行操作
?对链表的最后一个结点进行操作
? 最后一个结点的 next指针应为 NULL
? 可以定义一个结构体类型用于表示结点
的数据部分,以便于对数据的操作
C语言程序设计 - 第 8章 结构体 38
结束
The End