第十一章 结构体与共用体
§ 11.1 结构体
结构体是 一种 构造 数据类型
用途:把 不同类型 的数据组合成一个整体 -------
自定义 数据类型
结构体类型定义
struct [结构体名 ]
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};
成员类型可以是基本型或构造型struct是 关键字,
不能省略合法标识符可省,无名结构体例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
name
num
sex
age
score
addr
2字节
2字节
20字节
1字节
4字节
30字节

…..
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student stu1,stu2;
§ 11.2 结构体变量的定义
先定义结构体类型,再定义结构体变量
一般形式,struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};
struct 结构体名 变量名表列 ;
例 #define STUDENT struct student
STUDENT
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
STUDENT stu1,stu2;
定义结构体类型的同时定义结构体变量一般形式,struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}变量名表列 ;
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
直接定义结构体变量一般形式,struct
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}变量名表列 ;
例 struct
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
用 无名结构体 直接定义变量 只能一次
说明
结构体类型与结构体变量概念不同
类型,不分配内存 ; 变量,分配内存
类型,不能赋值、存取、运算 ; 变量,可以
结构体可嵌套
结构体成员名与程序中变量名可相同,不会混淆
结构体类型及变量的作用域与生存期例 struct date
{ int month;
int day;
int year;
};
struct student
{ int num;
char name[20];
struct date birthday;
}stu;
num name birthdaymonth day year
例 struct student
{ int num;
char name[20];
struct date
{ int month;
int day;
int year;
}birthday;
}stu;
num name birthdaymonth day year
§ 11.3 结构体变量的引用
引用规则
结构体变量 不能整体引用,只能引用变量 成员
可以将一个结 构体变量赋值给另一个结构体变量
结构体嵌套时 逐级引用成员 (分量 )运算符优先级,1
结合性,从左向右引用方式,结构体变量名,成员名例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
stu1.num=10;
stu1.score=85.5;
stu1.score+=stu2.score;
stu1.age++;
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
printf(“%d,%s,%c,%d,%f,%s \n”,stu1); (?)
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
stu2=stu1; ( )
例 struct student
{ int num;
char name[20];
struct date
{ int month;
int day;
int year;
}birthday;
}stu1,stu2;
num name birthdaymonth day year
stu1.birthday.month=12;
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
if(stu1==stu2)
…….,(?)
§ 11.4 结构体变量的初始化
形式一,struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};
struct 结构体名 结构体变量 ={初始数据 };
例 struct student
{ int num;
char name[20];
char sex;
int age;
char addr[30];
};
struct student stu1={112,“Wang Lin”,?M?,19,“200 Beijing Road”};
形式二:
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}结构体变量 ={初始数据 };
例 struct student
{ int num;
char name[20];
char sex;
int age;
char addr[30];
}stu1={112,“Wang Lin”,?M?,19,“200 Beijing Road”};
形式三:
struct
{
类型标识符 成员名;
类型标识符 成员名;
…………….
}结构体变量 ={初始数据 };
例 struct
{ int num;
char name[20];
char sex;
int age;
char addr[30];
}stu1={112,“Wang Lin”,?M?,19,“200 Beijing Road”};
§ 11.5 结构体数组
结构体数组的定义三种形式:
形式一,
struct student
{ int num;
char name[20];
char sex;
int age;
};
struct student stu[2];
形式二,
struct student
{ int num;
char name[20];
char sex;
int age;
}stu[2];
形式三,
struct
{ int num;
char name[20];
char sex;
int age;
}stu[2];
num
name
sex
age
num
name
sex
age
stu[0]
stu[1]
25B
结构体数组初始化例 struct
{ int num;
char name[20];
char sex;
int age;
}stu[ ]={{……},{……},{……}};
顺序初始化,
struct student
{ int num;
har name[20];
char sex;
int age;
};
struct student stu[ ]={100,“Wang Lin”,?M?,20,
101,“Li Gang”,?M?,19,
110,“Liu Yan”,?F?,19};
例 struct st dent
{ int num;
name[20];
char sex;
int age;
}s u[ ]={{……},{……},{……}};
分行初始化,
struct student
{ int nu ;
char name[20];
char sex;
int age;
};
struct student stu[ ]={{100,“Wang Lin”,,20},
{101,“Li Gang”,,19},
{110,“Liu Yan”,?F?,19}};
全部初始化时维数可省
结构体数组引用引用方式,结构体数组名 [下标 ].成员名
struct student
{ int num;
char name[20];
char sex;
int age;
}str[3];
stu[1].age++;
strcpy(stu[0].name,”ZhaoDan”);
§ 11.6 结构体和指针
指向结构体变量的指针
定义形式,struct 结构体名 *结构体指针名 ;
例 struct student *p;
使用结构体指针变量引用成员形式 存放结构体变量在内存的起始地址
num
name
sex
age
stu
pstruct student{ int num;
char name[20];
char sex;
int age;
}stu;
struct student *p=&stu;
(*结构体指针名 ).成员名 结构体指针名 ->成员名 结构体变量名,成员名指向运算符优先级,1
结合方向:从左向右例 指向结构体的指针变量
main()
{ struct student
{ long int num;
char name[20];
char sex;
float score;
}stu_1,*p;
p=&stu_1;
stu_1.num=89101;
strcpy(stu_1.name,"Li Lin");
p->sex='M';
p->score=89.5;
printf("\nNo:%ld\nname:%s\nsex:%c\nscore:%f\n",
(*p).num,p->name,stu_1.sex,p->score);
}
例 int n;
int *p=&n;
*p=10;? n=10
struct student stu1;
struct student *p=&stu1;
stu1.num=101;? (*p).num=101
指向结构体数组的指针例 指向结构体数组的指针
struct student
{ int num;
char name[20];
char sex;
int age;
}stu[3]={{10101,"Li Lin",'M',18},
{10102,"Zhang Fun",'M',19},
{10104,"Wang Min",'F',20}};
main()
{ struct student *p;
for(p=stu;p<stu+3;p++)
printf("%d%s%c%d\n",p->num,p->name,p->sex,p->age);
}
num
name
sex
age
stu[0]
p
stu[1]
stu[2]
p+1
11.7.1 动态存储分配和链表的概念动态存储分配:
由程序员控制的存储分配方法,根据需要临时分配内存单元以存放有用数据,当不用时,又可以释放存储单元,以便其用于分配给其它数据使用。
链表:
链表是动态进行存储分配的一种结构。若干数据 (每个数据组称为一个结点 )按一定的原则连接起来。
§ 11.7 动态存储分配 —链表
11.7.1 动态存储分配和链表的概念
1249 A
1356
B
1475
C
1021
D
NULL
head 1249 1356 1475 1021
简单的链表,
设置一指针变量,存放第一个结点的地址,
称为头指针,一般以 head命名。
最后一个结点的地址项不指向任何结点,
赋以值 NULL。
链表中每一个元素称为一个结点,结点是一组数据,包括用户需要的实际数据和下一个结点的地址。
前一个结点指向下一个结点,只有通过前一个结点才能找到下一个结点。
11.7.1 动态存储分配和链表的概念用 c语言实现链表结构,
包含指针项的 结构体 就是一个结点。
定义结点:
struct student
{int num;
float score;
struct student *next;
};
3010 99101
89.5
3028
head 3010 99103
90
4016
3028
99107
85
4016
NULL
A B C
num
score
next
11.7.2 简单链表例 11.7建立一个简单链表定义结点:
struct student
{long num;
float score;
struct student *next;
}a,b,c,*head;
赋予有用数据:
a.num=99101; a.score=89.5; b.num=99103;
b.score=90; c.num=99107; c.score=85;
建立链表:
head=&a; a.next=&b;b.next=&c;
c.next=0;
11.7.3 用于动态链表的函数
§ C标准函数库中动态存储分配的函数,
malloc( ) calloc( )
malloc函数
作用,
在内存中开辟指定大小的存储空间,并将此存储空间的起始地址作为函数返回值,
malloc函数的使用,
malloc(8)开辟长度为 8个字节的存储空间,若其起始地址为 1268,则 malloc(8)的返回值为 1268,且返回的指针值指向 void型,将此地址赋给一个指向 long型的指针变量,
p=(long *)malloc(8);
开辟一个结点,
malloc(sizeof(struct student));
11.7.3 用于动态链表的函数
calloc函数,
分配 num个大小为 size字节的空间,函数返回值为该空间的起始地址,
函数的作用,
函数的使用,
calloc(10,20) 开辟 10个大小为 20字节的空间,函数返回该空间的起始地址,
链表应用
§ 链表的特点,
链表每一个结点内必须包括一个指针项,指向下一结点,
链表所占内存区大小不固定,各结点在内存中的次序可以是任意的,
必须用 malloc和 calloc函数动态开辟单元,且开辟的结点只能用指针方法访问,
若断开链表中某一个结点,其后的所有结点虽在内存中存在,但无法访问,
单向链表最后一个结点的指针项必须是 NULL,
单向链表的访问只能从头指针开始,顺序进行,
例:以下程序运行后的输出结果是 ______。
#include <stdlib>
struct NODE
{int num;
struct NODE *next;
}
main()
{ struct NODE *p,*q,*r;
p=(struct NODE *)malloc(sizeof(struct NODE));
q=(struct NODE *)malloc(sizeof(struct NODE));
r=(struct NODE *)malloc(sizeof(struct NODE));
p->num=10;q->num=20;r->num=30;
p->next=q;q->next=r;
printf("%d\n",p->num+q->next->num);
}
A) 10 B) 20 C) 30 D) 40
D
例:若以下定义,struct link
{ int data;
struck link *next;
}a,b,c,*p,*q;
且变量 a和 b之间已有如下图所示的链表结构,指针 p指向变量 a,
q指向变量 c。则能够把 c插入到 a和 b 之间并形成新的链表的语句组是 ____
a b
data next data next
↑p c
data next
↑q
A) a.next=c; c.next=b; B) p.next=q; q.next=p.next;
C) p->next=&c; q->next=p->next; D) (*p).next=q; (*q).next=&b;
5 9
7
D
例:假定建立了以下链表结构,指针 p,q分别指向如图所示的结点,则以下可以将 q所指结点从链表中删除并释放该结点的语句组是 ______
A) free(q); p->next=q->next;
B) (*p).next=(*q).next; free(q);
C) q=(*q).next; (*p).next=q; free(q);
D) q=q->next; p->next=q; p=p->next; free(p);
8
data next
4
data next
3
data next
head
↑p ↑q
B
§ 11.8 共用体
构造数据类型,也叫联合体
用途:使几个不同类型的变量共占一段内存 (相互覆盖 )
共用体类型定义定义形式,union 共用体名
{
类型标识符 成员名;
类型标识符 成员名;
…………….
};例 union data
{ int i;
char ch;
float f;
}; f
ch
i 类型定义 不分配内存形式一,
union data
{ int i;
char ch;
float f;
}a,b;
形式二,
union data
{ int i;
char ch;
float f;
};
union data a,b,c,*p,d[3];
形式三,
union
{ int i;
char ch;
float f;
}a,b,c;
共用体变量的定义
f
ch
i
f
ch
i
a b
共用体 变量定义 分配内存,
长度 =最长成员 所占字节数共用体 变量任何时刻只有 一个成员 存在
共用体变量引用
引用方式:
例 a.i=1;
a.ch=?a?;
a.f=1.5;
printf(“%d”,a.i); (?编译通过,运行结果不对 )
引用规则
不能引用共用体变量,只能 引用其成员共用体指针名 ->成员名共用体变量名,成员名 (*共用体指针名 ).成员名
union data
{ int i;
char ch;
float f;
};
union data a,b,c,*p,d[3];
a.i a.ch a.f
p->i p->ch p->f
(*p).i (*p).ch (*p).f
d[0].i d[0].ch d[0].f
共用体变量中起作用的成员是 最后一次存放的成员例 union
{ int i;
char ch
float f;
}a;
a=1; (?)
不能 在定义共用体变量时 初始化例 union
{ int i;
char ch;
float f;
}a={1,?a?,1.5}; (?)
可以用一个共用体变量为另一个变量赋值例 float x;
union
{ int i; char ch; float f;
}a,b;
a.i=1; a.ch=?a?; a.f=1.5;
b=a; (?)
x=a.f; (?)
结构体与共用体
区别,存储方式不同
struct node
{ char ch[2];
int k;
}a;
union node
{ char ch[2];
int k;
}b;
achk
bch k
变量的各成员同时存在任一时刻只有一个成员存在
联系,两者可相互嵌套例 结构体中嵌套共用体
name num sex job class position
Li
Wang
1011
2086
F
M
S
T
501
prof
struct
{ char name[10];
int num;
char sex;
char job;
union
{ int class;
char position[10];
}category;
}person[2];
11.9 用 typedef定义类型
§ typedef可以定义新的类型名来代替已有的类型名,
简单的名字代替,
typedef int INTEGER;
INTEGER a,b;
定义一个类型名代表一个结构体,
typedef struct
{…… }STUDENT;
STUDENT studend1,student2,*p;