第十一章 结构体与共用体
一,结构体 的概念及使用
二,共用体 的概念及使用
三,链表 的概念及基本操作
四,11.9 枚举类型
五,11.10 用 typedef定义类型
自
己
阅
读
C
数
据
类
型
基本类型
构造类型
指针类型
空类型 void
定义类型 typedef
数值类型
字符类型 char
枚举类型 enum
整 型
浮点型
单精度型 float
双精度型 double
短整型 short
长整型 long
整型 int
数组
结构体 struct
共用体 union
<
C语言程序设计 第一章 C语言概述
在基本
类型基
础上自
己定义
的
我们首先来考虑一个问题。
一个学生的基本信息包括,
学号、姓名、性别、年龄、成绩、住址等。
这几项内容对一名学生来说是一个整体,它们可以
反映出学生的基本情况,如果用单个变量分别表示
这几项,例如,
sum:学号 name[10],姓名 sex,性别
age,年龄 score,成绩 addr[30],住址
不能体现出它们之间的内在联系。
所以,希望有一种变量,来表示所有这些数据,也就是,
把这些基本变量,作为一个整体构成一个新的变量,这
种变量就是我们要介绍的结构体变量。
第十一章 结构体与共用体
§ 11.1 结构体
?结构体是 一种 构造 数据类型
?用途:把 不同类型 的数据组合成一个整体 -------
自定义 数据类型
?结构体类型定义
struct [结构体名 ]
{
类型标识符 成员名;
类型标识符 成员名;
……………,
};
成员类型可以是
基本型或构造型 struct是 关键字,
不能省略
合法标识符
可省,无名结构体
分号不能省略
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}; 结构体类型定义描述结构
的组织形式,不分配内存
例如:要想把学生基本情况作为一个整体
加以处理,比如:学号、姓名、性别,
年龄、成绩、住址等。必须定义结构体类型
例
struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student stu1,stu2;
§ 11.2 结构体变量的定义
1、先定义结构体类型,再定义结构体变量
?一般形式,
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
……………,
};
struct 结构体名 变量名表列 ;
定义结构体变
量之后为其分
配内存单元
name
num
sex
age
score
addr
2字节
2字节
20字节
1字节
4字节
30字节
…
…..
stu1
2、定义结构体类型的同时定义结构体变量
一般形式,
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
……………,
}变量名表列 ;
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
3、直接定义结构体变量
一般形式,struct
{
类型标识符 成员名;
类型标识符 成员名;
……………,
}变量名表列 ;
例 struct
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
用 无名结构体 直接定义
变量 只能一次
?说明
?结构体类型与结构体变量概念不同
?类型,不分配内存 ; 变量,分配内存
?结构体类型是一个模型,类似系统给定的基本类型比如 int,
float 等类型,只是结构体类型是用户自定义的而已。
?结构体可嵌套
?结构体成员名与程序中变量名可相同,不会混淆
例 struct date
{ int month;
int day;
int year;
};
struct student
{ int num;
char name[20];
struct date birthday;
}stu;
num name birthday month 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); (?)
stu1={101,“Wan Lin”,?M?,19,87.5,“DaLian”}; (?)
例 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 birthday month day year
stu1.birthday.month=12;
§ 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[30];
形式二
struct student
{ int n ;
c ar a e[20];
c ar se ;
int a e;
}stu[30];
形式三,
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;
char 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 student
{ int num;
name[20];
char s x;
int age;
}stu[ ]={{……},{……},{……}};
分行初始化,
struct student
{ int nu ;
char na e[20];
char sex;
int age;
};
struct student stu[ ]={{100,,ang Lin”,? ?,20},
{101,“Li Gang”,? ?,19},
{110,“Liu Yan”,?F?,19}};
全部初始化时维数可省
?结构体数组引用
引用方式,结构体数组名 [下标 ].成员名
stru t student
{ int num;
char name[20];
char sex;
int age;
}str[3];
stu[1].age++;
strcpy(stu[0].name,”ZhaoDa”);
Str[0].name=“ZhaoDa” ×
例 统计后选人选票
#include <string.h>
struct person
{ char name[20];
int count;
}leader[3]={“Li”,0,“Zhang”,0,”Wang“,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);
}
Li
Zhang
Wang
0
0
0
name count
运行情况,
Li
Li
Wang
Zhang
…,
Li, 4
Zhang, 3
Wang, 3
§ 11.6 结构体和指针
?指向结构体变量的指针
?定义形式,struct 结构体名 *结构体指针名 ;
例 struct student *p;
?使用结构体指针变量引用成员形式 存放结构体变量在内存的起始地址
num
name
sex
age
stu
p struct student { int num;
char name[20];
char sex;
int age;
}stu;
struct student *p=&stu;
(*结构体指针名 ).成员名 结构体指针名 ->成员名 结构体变量名,成员名
指向运算符
优先级, 1
结合方向:从左向右
例 指向结构体的指针变量
#include<stdio.h>
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
?用指向结构体的指针作函数参数
?用结构体变量的成员作参数 ----值传递
?用指向结构体变量或数组的指针作参数 ----地址传递
?用结构体变量作参数 ---- 值传递,效率低
struct student void f(struct student stu2)
{ …,{
}stu1={….}; ….,
main() }
{….,
f(stu1);
…
}
struct student void f(struct student *p)
{ …,{
}stu1={….}; ….,
main() }
{….,
f(&stu);
…
}
struct student void f(long num)
{long num; {
char name[10];
}stu1={….}; ….,
main() }
{….,
f(stu1.num);
…
}
§ 11.8 共用体
?构造数据类型,也叫联合体
?用途:使几个不同类型的变量共占一段内存 (相互覆盖 )
?共用体类型定义
定义形式,union 共用体名 {
类型标识符 成员名;
类型标识符 成员名;
……………,
};
例 union data
{ int i;
char ch;
float f;
};
类型定义
不分配内存
2001
2002
2004
2003
ch
i
f
形式一,
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
共用体 变量定义 分配内存,
长度 =最长成员 所占字节数
共用体 变量任何时刻
只有 一个成员 存在
?共用体变量引用
?引用方式,
?引用规则
?不能引用共用体变量,只能 引用其成员
共用体指针名 ->成员名 共用体变量名,成员名 (*共用体指针名 ).成员名
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; (?)
§ 11.11链表
概念,对于数组,编译系统为其分配连续的一片存储单元,而链表,通过动
态分配内存,实现链表中各元素(结点)的数据存放在非连 续的单元
中,
如,
struct student
{ int num;
char name[10];
struct student *next; /* next 是指向该结构体类型的指针变量,
}; 用来存放下一个结点的起始地址,
实现将各结点连接成链 */
05001
Li li
2000
05002
Wang
3050
05003
Zhang
3060
1204 2000 3050 3060
1204
head
05003
Zhang
NULL
?动态分配内存函数,
格式 1,viod *malloc(unsigned int size)
功能,在内存的动态存储区中分配长度为 size(单位,byte)
连续空间,返回该连续域的 首地址 (是无类型指针);
未成功,返回 0。
struct student
{ int num;
char name[10];
struct student *next;
} *pt;
pt=(struct student *) malloc(sizeof(struct student))
pt num
name[10]
next
格式 2,calloc(n,size)
功能:与 malloc(size) 相同,区别是分配 n个长度为 size 的
连续空间。可以为一为数组开辟动态存储空间。
int *p;
p=(int *)calloc(3,sizeof(int))
p
格式, viod free(viod *p)
功能,释放由 p 指向的内存区,使这部分内存区能被其它变
量使用。 P 是最近一次调用 calloc 或 malloc 函数时返回的值。
free 无返回值。 例如, free(p);
建立动态链表
例题:写一个函数建立一个有若干名学生数据的单向动态链表,
当学号为 0 建表结束。
设结点的结构体类型如下,
struct student
{long num ;
float score ;
struct student *next ;
};
num
score
next
实现此要求的算法如下,
开辟一个新结点,并使 p1,p2指向它
读入一个学生数据给 p1所指的结点
head=NULL,n=0
当读入的 p1 - >num 不是零
n=n+1
n=1
head=p1 p2 - >next=p1
/* 把 p1所指的结点 /* 把 p1所指的结点
作为第一个结点 */ 连接到表尾 */
p2=p1 /* p2移到表尾 */
再开辟一个新结点,使 p1指向它
读入一个学生数据给 p1所指结点
p2->next=NULL /*表尾结点的指针变量置 NULL*/
真 假
head
p1
p2
null
①
99101
89.5
head
p2
p1
99103
78
②
n=1
99103
78
99103
78
head
p2
99101
89.5
p1
③ n=2
建立链表的函数可以如下,
#define NULL 0 while(p1->num!=0)
#define LEN sizeof(struct student) {n=n+1;
struct student if(n= =1)head=p1;
{long num; else p2->next=p1;
float score; p2=p1;
struct student *next; p1=(struct student *)malloc(LEN);
}; scanf(“%ld,%f”,&p1->num,&p1->score);
int n; }
struct student *creat(void) p2->next=NULL;
{struct strudent *head; return(head);
struct student *p1,*p2; }
n=0;
p1=p2=(struct student *)malloc(LEN);
scanf(“%ld,%f”,&p1->.num,&p1->score);
head=NULL;
可以在主函数中调用函数 creat,例如,
main()
{
……
creat();
}
输出链表
例题:编写一个输出链表的函数 print
void print(struct student *head) 在主函数中调用
{struct student *p; 方式
printf(“\n Now,These %d records are:\n”,n); main()
p=head; {
if(head!=NULL) ……,
do print(head);
{printf(“%ld5.1f\n”,p->num,p->score); ………
p=p->next; }
}while (p!=NULL); }
04001
90
2800
04001
90
3000
04001
90
NULL
04001
90
2000
head 1000
2000 2800 3000
1000
对链表的删除操作
例题:写一函数以删除动态链表中指定的结点。函数 del 如下,
struct student *del(struct student *head,long num)
{struct student *p1,*p2;
if (head= =NULL){printf(“\nlist null!\n”); goto end;}
p1=head;
while(num!=p1->num && p1->next!=NULL)
{p2=p1; p1=p1->next;}
if(num= =p1->num)
{if(p1= =head)head=p1->next;
else p2->next=p1->next;
printf(“delete:%ld\n”,num);
n=n-1;
}
else printf(“%ld not been found!\n”,num);
end, return(head);
}
num
p1 p2
对链表的插入操作。 设已有一个学生链表,各结点是按其成员
项 num (学号)的值由小到大顺序排序的。今要插入一个新生的结点,要求按学
号的顺序插入。 插入函数 insert 如下,
struct student *insert(struct student *head,struct student *stud)
{struct student *p0,*p1,*p2 ;
p1=head ; p0=stud ;
if(head= =NULL)
{head=p0; p0->next=NULL;}
else
{while ((p0->num>p1->num) && (p1->next!=NULL))
{p2=p1; p1=p1->next;}
if(p0->num<=p1->num)
{ if(head= =p1) head=p0;
else p2->next=p0;
p0->next=p1;}
else
{p1->next=p0;p0->next=NULL;}}
n=n+1;
return(head);
}
p0
准备插入的节点
p2 p1
对链表的综合操作
将以上建立、输出、删除、插入的函数组织在一个程序中,用函数 main 作主
调函数。可以写出 main 函数 ( main函数的位置在以上个函数的后面)
main()
{struct student *head,stu;
long del_num;
printf(“input records:\n”);
head=creat(); print(head);
printf(“\n input the deleted number:”);
scanf(“%ld”,&del_num);
head=del(head,del_num); print(head);
printf(“\n input the inserted record,”);
scanf(“%ld,%f”,&stu.num,&stu.score);
head=insert(head,&stu); print(head);
}
通用的主函数为,
main()
{struct student *head,*stu; long del_num;
printf(“input records:\n”); head=creat(); print(head);
printf(“\n input the deleted number:”); scanf(“%ld”,&del_num);
while(del_num!=0)
{head=del(head,del_num);
printf(“input the deleted number:”); scanf(“%ld”,&del_num); }
printf(“\n input the inserted recored:”);
stu=(struct student *) malloc(LEN);
scanf(“%ld,%f”,&stu->num,&stu->score);
while(stu->num!=0)
{head=insert(head,stu);
printf(“input the inserted recored:”);
stu=(struct student *)malloc(LEN);
scanf(“%ld,%f”,&stu->num,&stu->score); }
}
作业,296页 11.3 预习实验,结构体 与共用体
写实验报告
例 将一个整数按字节输出
运行结果,
i=60501
ch0=101,ch1=141
ch0=A,ch1=a
main()
{ union int_char
{ int i;
char ch[2];
}x;
x.i=24897;
printf("i=%o\n",x.i);
printf("ch0=%o,ch1=%o\n
ch0=%c,ch1=%c\n",
x.ch[0],x.ch[1],x.ch[0],x.ch[1]);
}
01100001 01000001
低字节 高字节
01000001
01100001
ch[0]
ch[1]
2000
2001
i
?结构体与共用体
?区别, 存储方式不同
struct node
{ char ch[2];
int k;
}a;
union node
{ char ch[2];
int k;
}b;
a ch k
b ch k
变量的各成员同时存在
任一时刻只有一个成员存在
?联系, 两者可相互嵌套
?类比:结构体与共用体的定义形式类似,变量定义方
式类似,成员引用方式类似。
例 结构体中嵌套共用体
name num sex job class position
Li
Wang
1011
2086
F
M
S
T
501
prof
struct
{ int num;
char name[10];
char sex;
char job;
union
{ int class;
char position[10];
}category;
}person[2];
?建立链表
变量设置,
head——指向结构体类型指针变量,一般用它指向链表头。
p1——指向结构体类型指针变量,指向新的结点首地址。
p2——指向结构体类型指针变量,指向尾结点的首地址。
9909
,
,
9909
,
,
9910
,
,
9911
,
,
p1
p2
p2
p1
p2
p1 head
..,
定义 head
p1,p2,n=0
动态分配
输入结点内
数据 p2 ?next
NULL 返回 head
p1?num!=0?
n?n+1 动态分配
p2 ?p1 head ?p1
p2 ?next ?p1
n=1?
输入结点内数据
N
Y
N
Y
p1
n=1 n=2 n=3
#define LEN sizeof(struct student)
struct student
{ int num;
float aver;
struct student *next;
};
int n;
struct student *creat( ) /*该函数是建立链表的,它返回
的指针,是指向该链表在内存存放首地址 */
{ struct student *head,*p1,*p2;
n=0;
p1=p2=(struct student*)malloc(LEN); /*动态分配内存 */
scanf(“%d,%f”,&p1? num,&p1? aver); /*输入节点内数据 */
head =NULL; /*空表处理 */
while (p1? num!=0) /*判建立链表是否结束 */
{ n++;
if (n= =1) head=p1; /*第一个节点处理 */
else p2? next=p1; /*其他节点处理 */
p2=p1;
p1=(struct student *)malloc(LEN); /*动态分配内存 */
scanf(“%d,%f”,&p1? num,&p? aver);
}
p2? next=NULL; /*结束点,送 NULL*/
return(head);}
aver
next
num
head
aver
next
num p1
p1
aver
next
num
p1
1
1.5
head p2
p2
?输出链表
p?head
返回
输出数据
p? p?next
head!=NULL?
p!=NULL?
N
Y
N
Y
pri(head)
struct student *head;
{ struct student *p;
p=head;
if (head != NULL)
do
{ printf(“%d %f\n”,p? num,p? aver);
p= p? next;
}while(p != NULL);
}
?删除链表中结点
,,,
head
p2
p1
., ……
n=1 n=2 n=3
删除某结点,不是将此结点真正从内存清除,而是将该节点
在链表中的联系断开。 如:要删除第二个结点,就把第一个结
点最后的指针不是指第 2结点首地址,而指第 3个结点首地址。
程序中要考虑以下几种情况,
删除第一个结点,head ? head? next;
删除其它结点:(例删第二个结点 ) p2? next ? p1?next;
框图,
head!=NULL?
未找到与未结束?
找到
p1=head? p1? head
p2? p1,p1? p1? next
返回
p2?next ?p1? next
返回
n ? n-1
head ? p1? next
未找到
N 删其它结点
删头结点
Y
N 是空表
Y
N
struct student *del(struct student *head,int num)
{
struct student *p1,*p2;
if (head= =NULL) { printf(“list hull! \n”); return(head);}
p1=head;
while (num!= p1? num && p1? next!= NULL)
{p2=p1; p1=p2? next;} /*前进一个节点 */
if (num= =p1? num)
{ if (p1= =head) head =head? next; /*删头节点 */
else p2? next = p1? next; /*删其他节点 */
printf(“delete=%d\n”,num);
n=n-1;
}
else printf(“%d not been found !\n”,num);
return(head);
}
?链表中插入结点操作(从小到大)
在一个有序链表中,插入某结点后,也是有序表
是空表?
插入第一个结点?
找插入位置?
找到?
head?p0
p0 ? next ? NULL
p2?p1,p1?p2? next
p1? next?p0
p0? next?NULL
n?n+1
head?p0 p2? next?p0
p0? next?p1
Y
N
Y
N
Y
N
N
Y
插到最后
非空表
空表插入
第一个结点
p0—指向要插入的结点
程序中要考虑以下几种情况,
P0是要插入点,p1首先指向头结点。
是空表,将该结点插入,作为头结点。
非空表,插入位置是头结点,head?p0,p0? next ? p1
插入位置是非头,非尾结点( p2后,p1前),
p2? next ? p0,p0? next ? p1
插入位置是尾结点,p1? next ?p0,p0? next ?NULL
struct student *insert (struct student *head,struct student *stud)
{
struct student *p0,*p1,*p2;
p1=head;
p0=stud;
if (head= =NULL)
{head =p0; p0? next=NULL}; /*是空表 */
else
while ((p0? num > p1? num) && (p1? next != NULL))
{ p2=p1; p1=p2? next;} /*找插入位置 */
if (p0? num < = p1? num)
{ if (head = =p1) head=p0; /*插入非空表中第一个节点处 */
else p2? next=p0; /*插入非空表中非头,非尾节点 */
p0? next=p1;
}
else {p1? next=p0; p0? next=NULL;} /*插入链表最后 */
}
§ 11.10 用 typedef定义类型
?功能,用自定义名字为 已有 数据类型命名
?类型定义 简单形式,typedef type name;
例 typedef int INTEGER; 类型定义语句关键字 已有数据类型名 用户定义的类型名
例 typedef float REAL;
类型定义后,与已有类型一样使用
例 INTEGER a,b,c;
REAL f1,f2;
int a,b,c;
float f1,f2; 说明, 1.typedef 没有创造 新数据类型
2.typedef 是定义类型,不能定义变量
3.typedef 与 define 不同
define typedef
预编译时处理 编译时处理
简单字符置换 为已有类型命名
?typedef定义类型步骤
?按定义变量方法先写出定义体 如 int i;
?将变量名换成新类型名 如 int INTEGER;
?最前面加 typedef 如 typedef int INTEGER;
?用新类型名定义变量 如 INTEGER i,j;
例 定义数组类型
? int a[100];
? int ARRAY[100];
? typedef int ARRAY[100];
? ARRAY a,b,c;
? int a[100],b[100],c[100];
例 定义指针类型
char *str;
char *STRING;
typedef char *STRING;
ST ING p,s[10];
? char *p;
char *s[10];
例 定义函数指针类型
? int (*p)();
? int (*POWER)();
? typedef int (*POWER)();
?POWER p1,p2;
? int (*p1)(),(*p2)();
例 定义结构体类型
struct date
{ int month;
int day;
int year;
}d;
例 定义结构体类型
? struct date
{ int month;
int day;
int year;
}DATE;
例 定义结构体类型
?typedef struct date
{ int month;
int day;
int year;
}DATE;
例 定义结构体类型
? DATE birthday,*p;
? struct date
{ int month;
int day;
int year;
}birthday,*p;
?类型定义可嵌套
例 typedef struct club
{ char name[20];
int size;
int year;
}GROUP;
typedef GROUP *PG;
PG pclub;
? GROUP *pclub;
? struct club *pclub;
GROUP为结构体类型
PG为指向 GROUP的指针类型
§ 11.12 枚举
若某个变量只存在有限的几种取值。可定义成枚举类型;
例,enum weekday {sun,mon,twe,wed,thu,fri,set};
enum color {red,blue,while,black,yellow};
定义枚举类型和变量的格式同结构体和共用体。
枚举的成员按常量处理,不是变量(不能赋值),按顺序有固定的值
( 0,1-----),也可改变其值。
如,
enum weekday workday;
weekday=mon;
printf(“%d\n”,workday) /* 输出 1 */
若,
enum weekday {sun=7,mon=1,tue,wed,thu,fri,sat} workday;
workday=tue;
printf(“%d\n”,workday) /* 输出 2 */
workday=2; /*整型数不能直接赋值给枚举变量,类型不匹配 */
workday=(enum weekday)2; /* 可以赋值,相当于将顺序号为 2的枚举
元素赋给 workday */
例 袋中有红、黄、白、蓝、黑五种颜色的球。每次从袋
中取出 3个球,问得到三种不同颜色的球的可能取法,
输出每种组合的三种颜色。
main( )
{ enum color {red,yellow,blue,white,black};
enum color i,j,k,pri;
int n=0,loop;
for (i=red; i<= black; i++)
for (j=red; j<= black; j++)
if (i!=j)
{ for (k=red; k<= black; k++)
if ((k!=i) && (k!=j))
{ n=n+1;
printf(“%-4d”,n);
for (loop=1; loop<=3; loop++)
{ switch(loop)
{ case1,pri=i; break;
case2,pri=j; break;
case3,pri=k; break;
}
switch(pri)
{ case red,printf(%-10s”,”red”); break;
case yellow:printf(%-10s”,”yellow”); break;
case blue,printf(%-10s”,”blue”); break;
case white,printf(%-10s”,”white”); break;
case black,printf(%-10s”,”black”); break;
default,break;
}
}
printf(“\n”);
}
}
printf(“\n total:%5d\n”,n);
}
运行结果,
1 red yellow blue
2 red yellow white
3 red yellow black
4 red blue yellow
5 red blue white
6 red blue black
7,,,
一,结构体 的概念及使用
二,共用体 的概念及使用
三,链表 的概念及基本操作
四,11.9 枚举类型
五,11.10 用 typedef定义类型
自
己
阅
读
C
数
据
类
型
基本类型
构造类型
指针类型
空类型 void
定义类型 typedef
数值类型
字符类型 char
枚举类型 enum
整 型
浮点型
单精度型 float
双精度型 double
短整型 short
长整型 long
整型 int
数组
结构体 struct
共用体 union
<
C语言程序设计 第一章 C语言概述
在基本
类型基
础上自
己定义
的
我们首先来考虑一个问题。
一个学生的基本信息包括,
学号、姓名、性别、年龄、成绩、住址等。
这几项内容对一名学生来说是一个整体,它们可以
反映出学生的基本情况,如果用单个变量分别表示
这几项,例如,
sum:学号 name[10],姓名 sex,性别
age,年龄 score,成绩 addr[30],住址
不能体现出它们之间的内在联系。
所以,希望有一种变量,来表示所有这些数据,也就是,
把这些基本变量,作为一个整体构成一个新的变量,这
种变量就是我们要介绍的结构体变量。
第十一章 结构体与共用体
§ 11.1 结构体
?结构体是 一种 构造 数据类型
?用途:把 不同类型 的数据组合成一个整体 -------
自定义 数据类型
?结构体类型定义
struct [结构体名 ]
{
类型标识符 成员名;
类型标识符 成员名;
……………,
};
成员类型可以是
基本型或构造型 struct是 关键字,
不能省略
合法标识符
可省,无名结构体
分号不能省略
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}; 结构体类型定义描述结构
的组织形式,不分配内存
例如:要想把学生基本情况作为一个整体
加以处理,比如:学号、姓名、性别,
年龄、成绩、住址等。必须定义结构体类型
例
struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
struct student stu1,stu2;
§ 11.2 结构体变量的定义
1、先定义结构体类型,再定义结构体变量
?一般形式,
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
……………,
};
struct 结构体名 变量名表列 ;
定义结构体变
量之后为其分
配内存单元
name
num
sex
age
score
addr
2字节
2字节
20字节
1字节
4字节
30字节
…
…..
stu1
2、定义结构体类型的同时定义结构体变量
一般形式,
struct 结构体名
{
类型标识符 成员名;
类型标识符 成员名;
……………,
}变量名表列 ;
例 struct student
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
3、直接定义结构体变量
一般形式,struct
{
类型标识符 成员名;
类型标识符 成员名;
……………,
}变量名表列 ;
例 struct
{ int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
}stu1,stu2;
用 无名结构体 直接定义
变量 只能一次
?说明
?结构体类型与结构体变量概念不同
?类型,不分配内存 ; 变量,分配内存
?结构体类型是一个模型,类似系统给定的基本类型比如 int,
float 等类型,只是结构体类型是用户自定义的而已。
?结构体可嵌套
?结构体成员名与程序中变量名可相同,不会混淆
例 struct date
{ int month;
int day;
int year;
};
struct student
{ int num;
char name[20];
struct date birthday;
}stu;
num name birthday month 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); (?)
stu1={101,“Wan Lin”,?M?,19,87.5,“DaLian”}; (?)
例 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 birthday month day year
stu1.birthday.month=12;
§ 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[30];
形式二
struct student
{ int n ;
c ar a e[20];
c ar se ;
int a e;
}stu[30];
形式三,
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;
char 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 student
{ int num;
name[20];
char s x;
int age;
}stu[ ]={{……},{……},{……}};
分行初始化,
struct student
{ int nu ;
char na e[20];
char sex;
int age;
};
struct student stu[ ]={{100,,ang Lin”,? ?,20},
{101,“Li Gang”,? ?,19},
{110,“Liu Yan”,?F?,19}};
全部初始化时维数可省
?结构体数组引用
引用方式,结构体数组名 [下标 ].成员名
stru t student
{ int num;
char name[20];
char sex;
int age;
}str[3];
stu[1].age++;
strcpy(stu[0].name,”ZhaoDa”);
Str[0].name=“ZhaoDa” ×
例 统计后选人选票
#include <string.h>
struct person
{ char name[20];
int count;
}leader[3]={“Li”,0,“Zhang”,0,”Wang“,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);
}
Li
Zhang
Wang
0
0
0
name count
运行情况,
Li
Li
Wang
Zhang
…,
Li, 4
Zhang, 3
Wang, 3
§ 11.6 结构体和指针
?指向结构体变量的指针
?定义形式,struct 结构体名 *结构体指针名 ;
例 struct student *p;
?使用结构体指针变量引用成员形式 存放结构体变量在内存的起始地址
num
name
sex
age
stu
p struct student { int num;
char name[20];
char sex;
int age;
}stu;
struct student *p=&stu;
(*结构体指针名 ).成员名 结构体指针名 ->成员名 结构体变量名,成员名
指向运算符
优先级, 1
结合方向:从左向右
例 指向结构体的指针变量
#include<stdio.h>
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
?用指向结构体的指针作函数参数
?用结构体变量的成员作参数 ----值传递
?用指向结构体变量或数组的指针作参数 ----地址传递
?用结构体变量作参数 ---- 值传递,效率低
struct student void f(struct student stu2)
{ …,{
}stu1={….}; ….,
main() }
{….,
f(stu1);
…
}
struct student void f(struct student *p)
{ …,{
}stu1={….}; ….,
main() }
{….,
f(&stu);
…
}
struct student void f(long num)
{long num; {
char name[10];
}stu1={….}; ….,
main() }
{….,
f(stu1.num);
…
}
§ 11.8 共用体
?构造数据类型,也叫联合体
?用途:使几个不同类型的变量共占一段内存 (相互覆盖 )
?共用体类型定义
定义形式,union 共用体名 {
类型标识符 成员名;
类型标识符 成员名;
……………,
};
例 union data
{ int i;
char ch;
float f;
};
类型定义
不分配内存
2001
2002
2004
2003
ch
i
f
形式一,
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
共用体 变量定义 分配内存,
长度 =最长成员 所占字节数
共用体 变量任何时刻
只有 一个成员 存在
?共用体变量引用
?引用方式,
?引用规则
?不能引用共用体变量,只能 引用其成员
共用体指针名 ->成员名 共用体变量名,成员名 (*共用体指针名 ).成员名
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; (?)
§ 11.11链表
概念,对于数组,编译系统为其分配连续的一片存储单元,而链表,通过动
态分配内存,实现链表中各元素(结点)的数据存放在非连 续的单元
中,
如,
struct student
{ int num;
char name[10];
struct student *next; /* next 是指向该结构体类型的指针变量,
}; 用来存放下一个结点的起始地址,
实现将各结点连接成链 */
05001
Li li
2000
05002
Wang
3050
05003
Zhang
3060
1204 2000 3050 3060
1204
head
05003
Zhang
NULL
?动态分配内存函数,
格式 1,viod *malloc(unsigned int size)
功能,在内存的动态存储区中分配长度为 size(单位,byte)
连续空间,返回该连续域的 首地址 (是无类型指针);
未成功,返回 0。
struct student
{ int num;
char name[10];
struct student *next;
} *pt;
pt=(struct student *) malloc(sizeof(struct student))
pt num
name[10]
next
格式 2,calloc(n,size)
功能:与 malloc(size) 相同,区别是分配 n个长度为 size 的
连续空间。可以为一为数组开辟动态存储空间。
int *p;
p=(int *)calloc(3,sizeof(int))
p
格式, viod free(viod *p)
功能,释放由 p 指向的内存区,使这部分内存区能被其它变
量使用。 P 是最近一次调用 calloc 或 malloc 函数时返回的值。
free 无返回值。 例如, free(p);
建立动态链表
例题:写一个函数建立一个有若干名学生数据的单向动态链表,
当学号为 0 建表结束。
设结点的结构体类型如下,
struct student
{long num ;
float score ;
struct student *next ;
};
num
score
next
实现此要求的算法如下,
开辟一个新结点,并使 p1,p2指向它
读入一个学生数据给 p1所指的结点
head=NULL,n=0
当读入的 p1 - >num 不是零
n=n+1
n=1
head=p1 p2 - >next=p1
/* 把 p1所指的结点 /* 把 p1所指的结点
作为第一个结点 */ 连接到表尾 */
p2=p1 /* p2移到表尾 */
再开辟一个新结点,使 p1指向它
读入一个学生数据给 p1所指结点
p2->next=NULL /*表尾结点的指针变量置 NULL*/
真 假
head
p1
p2
null
①
99101
89.5
head
p2
p1
99103
78
②
n=1
99103
78
99103
78
head
p2
99101
89.5
p1
③ n=2
建立链表的函数可以如下,
#define NULL 0 while(p1->num!=0)
#define LEN sizeof(struct student) {n=n+1;
struct student if(n= =1)head=p1;
{long num; else p2->next=p1;
float score; p2=p1;
struct student *next; p1=(struct student *)malloc(LEN);
}; scanf(“%ld,%f”,&p1->num,&p1->score);
int n; }
struct student *creat(void) p2->next=NULL;
{struct strudent *head; return(head);
struct student *p1,*p2; }
n=0;
p1=p2=(struct student *)malloc(LEN);
scanf(“%ld,%f”,&p1->.num,&p1->score);
head=NULL;
可以在主函数中调用函数 creat,例如,
main()
{
……
creat();
}
输出链表
例题:编写一个输出链表的函数 print
void print(struct student *head) 在主函数中调用
{struct student *p; 方式
printf(“\n Now,These %d records are:\n”,n); main()
p=head; {
if(head!=NULL) ……,
do print(head);
{printf(“%ld5.1f\n”,p->num,p->score); ………
p=p->next; }
}while (p!=NULL); }
04001
90
2800
04001
90
3000
04001
90
NULL
04001
90
2000
head 1000
2000 2800 3000
1000
对链表的删除操作
例题:写一函数以删除动态链表中指定的结点。函数 del 如下,
struct student *del(struct student *head,long num)
{struct student *p1,*p2;
if (head= =NULL){printf(“\nlist null!\n”); goto end;}
p1=head;
while(num!=p1->num && p1->next!=NULL)
{p2=p1; p1=p1->next;}
if(num= =p1->num)
{if(p1= =head)head=p1->next;
else p2->next=p1->next;
printf(“delete:%ld\n”,num);
n=n-1;
}
else printf(“%ld not been found!\n”,num);
end, return(head);
}
num
p1 p2
对链表的插入操作。 设已有一个学生链表,各结点是按其成员
项 num (学号)的值由小到大顺序排序的。今要插入一个新生的结点,要求按学
号的顺序插入。 插入函数 insert 如下,
struct student *insert(struct student *head,struct student *stud)
{struct student *p0,*p1,*p2 ;
p1=head ; p0=stud ;
if(head= =NULL)
{head=p0; p0->next=NULL;}
else
{while ((p0->num>p1->num) && (p1->next!=NULL))
{p2=p1; p1=p1->next;}
if(p0->num<=p1->num)
{ if(head= =p1) head=p0;
else p2->next=p0;
p0->next=p1;}
else
{p1->next=p0;p0->next=NULL;}}
n=n+1;
return(head);
}
p0
准备插入的节点
p2 p1
对链表的综合操作
将以上建立、输出、删除、插入的函数组织在一个程序中,用函数 main 作主
调函数。可以写出 main 函数 ( main函数的位置在以上个函数的后面)
main()
{struct student *head,stu;
long del_num;
printf(“input records:\n”);
head=creat(); print(head);
printf(“\n input the deleted number:”);
scanf(“%ld”,&del_num);
head=del(head,del_num); print(head);
printf(“\n input the inserted record,”);
scanf(“%ld,%f”,&stu.num,&stu.score);
head=insert(head,&stu); print(head);
}
通用的主函数为,
main()
{struct student *head,*stu; long del_num;
printf(“input records:\n”); head=creat(); print(head);
printf(“\n input the deleted number:”); scanf(“%ld”,&del_num);
while(del_num!=0)
{head=del(head,del_num);
printf(“input the deleted number:”); scanf(“%ld”,&del_num); }
printf(“\n input the inserted recored:”);
stu=(struct student *) malloc(LEN);
scanf(“%ld,%f”,&stu->num,&stu->score);
while(stu->num!=0)
{head=insert(head,stu);
printf(“input the inserted recored:”);
stu=(struct student *)malloc(LEN);
scanf(“%ld,%f”,&stu->num,&stu->score); }
}
作业,296页 11.3 预习实验,结构体 与共用体
写实验报告
例 将一个整数按字节输出
运行结果,
i=60501
ch0=101,ch1=141
ch0=A,ch1=a
main()
{ union int_char
{ int i;
char ch[2];
}x;
x.i=24897;
printf("i=%o\n",x.i);
printf("ch0=%o,ch1=%o\n
ch0=%c,ch1=%c\n",
x.ch[0],x.ch[1],x.ch[0],x.ch[1]);
}
01100001 01000001
低字节 高字节
01000001
01100001
ch[0]
ch[1]
2000
2001
i
?结构体与共用体
?区别, 存储方式不同
struct node
{ char ch[2];
int k;
}a;
union node
{ char ch[2];
int k;
}b;
a ch k
b ch k
变量的各成员同时存在
任一时刻只有一个成员存在
?联系, 两者可相互嵌套
?类比:结构体与共用体的定义形式类似,变量定义方
式类似,成员引用方式类似。
例 结构体中嵌套共用体
name num sex job class position
Li
Wang
1011
2086
F
M
S
T
501
prof
struct
{ int num;
char name[10];
char sex;
char job;
union
{ int class;
char position[10];
}category;
}person[2];
?建立链表
变量设置,
head——指向结构体类型指针变量,一般用它指向链表头。
p1——指向结构体类型指针变量,指向新的结点首地址。
p2——指向结构体类型指针变量,指向尾结点的首地址。
9909
,
,
9909
,
,
9910
,
,
9911
,
,
p1
p2
p2
p1
p2
p1 head
..,
定义 head
p1,p2,n=0
动态分配
输入结点内
数据 p2 ?next
NULL 返回 head
p1?num!=0?
n?n+1 动态分配
p2 ?p1 head ?p1
p2 ?next ?p1
n=1?
输入结点内数据
N
Y
N
Y
p1
n=1 n=2 n=3
#define LEN sizeof(struct student)
struct student
{ int num;
float aver;
struct student *next;
};
int n;
struct student *creat( ) /*该函数是建立链表的,它返回
的指针,是指向该链表在内存存放首地址 */
{ struct student *head,*p1,*p2;
n=0;
p1=p2=(struct student*)malloc(LEN); /*动态分配内存 */
scanf(“%d,%f”,&p1? num,&p1? aver); /*输入节点内数据 */
head =NULL; /*空表处理 */
while (p1? num!=0) /*判建立链表是否结束 */
{ n++;
if (n= =1) head=p1; /*第一个节点处理 */
else p2? next=p1; /*其他节点处理 */
p2=p1;
p1=(struct student *)malloc(LEN); /*动态分配内存 */
scanf(“%d,%f”,&p1? num,&p? aver);
}
p2? next=NULL; /*结束点,送 NULL*/
return(head);}
aver
next
num
head
aver
next
num p1
p1
aver
next
num
p1
1
1.5
head p2
p2
?输出链表
p?head
返回
输出数据
p? p?next
head!=NULL?
p!=NULL?
N
Y
N
Y
pri(head)
struct student *head;
{ struct student *p;
p=head;
if (head != NULL)
do
{ printf(“%d %f\n”,p? num,p? aver);
p= p? next;
}while(p != NULL);
}
?删除链表中结点
,,,
head
p2
p1
., ……
n=1 n=2 n=3
删除某结点,不是将此结点真正从内存清除,而是将该节点
在链表中的联系断开。 如:要删除第二个结点,就把第一个结
点最后的指针不是指第 2结点首地址,而指第 3个结点首地址。
程序中要考虑以下几种情况,
删除第一个结点,head ? head? next;
删除其它结点:(例删第二个结点 ) p2? next ? p1?next;
框图,
head!=NULL?
未找到与未结束?
找到
p1=head? p1? head
p2? p1,p1? p1? next
返回
p2?next ?p1? next
返回
n ? n-1
head ? p1? next
未找到
N 删其它结点
删头结点
Y
N 是空表
Y
N
struct student *del(struct student *head,int num)
{
struct student *p1,*p2;
if (head= =NULL) { printf(“list hull! \n”); return(head);}
p1=head;
while (num!= p1? num && p1? next!= NULL)
{p2=p1; p1=p2? next;} /*前进一个节点 */
if (num= =p1? num)
{ if (p1= =head) head =head? next; /*删头节点 */
else p2? next = p1? next; /*删其他节点 */
printf(“delete=%d\n”,num);
n=n-1;
}
else printf(“%d not been found !\n”,num);
return(head);
}
?链表中插入结点操作(从小到大)
在一个有序链表中,插入某结点后,也是有序表
是空表?
插入第一个结点?
找插入位置?
找到?
head?p0
p0 ? next ? NULL
p2?p1,p1?p2? next
p1? next?p0
p0? next?NULL
n?n+1
head?p0 p2? next?p0
p0? next?p1
Y
N
Y
N
Y
N
N
Y
插到最后
非空表
空表插入
第一个结点
p0—指向要插入的结点
程序中要考虑以下几种情况,
P0是要插入点,p1首先指向头结点。
是空表,将该结点插入,作为头结点。
非空表,插入位置是头结点,head?p0,p0? next ? p1
插入位置是非头,非尾结点( p2后,p1前),
p2? next ? p0,p0? next ? p1
插入位置是尾结点,p1? next ?p0,p0? next ?NULL
struct student *insert (struct student *head,struct student *stud)
{
struct student *p0,*p1,*p2;
p1=head;
p0=stud;
if (head= =NULL)
{head =p0; p0? next=NULL}; /*是空表 */
else
while ((p0? num > p1? num) && (p1? next != NULL))
{ p2=p1; p1=p2? next;} /*找插入位置 */
if (p0? num < = p1? num)
{ if (head = =p1) head=p0; /*插入非空表中第一个节点处 */
else p2? next=p0; /*插入非空表中非头,非尾节点 */
p0? next=p1;
}
else {p1? next=p0; p0? next=NULL;} /*插入链表最后 */
}
§ 11.10 用 typedef定义类型
?功能,用自定义名字为 已有 数据类型命名
?类型定义 简单形式,typedef type name;
例 typedef int INTEGER; 类型定义语句关键字 已有数据类型名 用户定义的类型名
例 typedef float REAL;
类型定义后,与已有类型一样使用
例 INTEGER a,b,c;
REAL f1,f2;
int a,b,c;
float f1,f2; 说明, 1.typedef 没有创造 新数据类型
2.typedef 是定义类型,不能定义变量
3.typedef 与 define 不同
define typedef
预编译时处理 编译时处理
简单字符置换 为已有类型命名
?typedef定义类型步骤
?按定义变量方法先写出定义体 如 int i;
?将变量名换成新类型名 如 int INTEGER;
?最前面加 typedef 如 typedef int INTEGER;
?用新类型名定义变量 如 INTEGER i,j;
例 定义数组类型
? int a[100];
? int ARRAY[100];
? typedef int ARRAY[100];
? ARRAY a,b,c;
? int a[100],b[100],c[100];
例 定义指针类型
char *str;
char *STRING;
typedef char *STRING;
ST ING p,s[10];
? char *p;
char *s[10];
例 定义函数指针类型
? int (*p)();
? int (*POWER)();
? typedef int (*POWER)();
?POWER p1,p2;
? int (*p1)(),(*p2)();
例 定义结构体类型
struct date
{ int month;
int day;
int year;
}d;
例 定义结构体类型
? struct date
{ int month;
int day;
int year;
}DATE;
例 定义结构体类型
?typedef struct date
{ int month;
int day;
int year;
}DATE;
例 定义结构体类型
? DATE birthday,*p;
? struct date
{ int month;
int day;
int year;
}birthday,*p;
?类型定义可嵌套
例 typedef struct club
{ char name[20];
int size;
int year;
}GROUP;
typedef GROUP *PG;
PG pclub;
? GROUP *pclub;
? struct club *pclub;
GROUP为结构体类型
PG为指向 GROUP的指针类型
§ 11.12 枚举
若某个变量只存在有限的几种取值。可定义成枚举类型;
例,enum weekday {sun,mon,twe,wed,thu,fri,set};
enum color {red,blue,while,black,yellow};
定义枚举类型和变量的格式同结构体和共用体。
枚举的成员按常量处理,不是变量(不能赋值),按顺序有固定的值
( 0,1-----),也可改变其值。
如,
enum weekday workday;
weekday=mon;
printf(“%d\n”,workday) /* 输出 1 */
若,
enum weekday {sun=7,mon=1,tue,wed,thu,fri,sat} workday;
workday=tue;
printf(“%d\n”,workday) /* 输出 2 */
workday=2; /*整型数不能直接赋值给枚举变量,类型不匹配 */
workday=(enum weekday)2; /* 可以赋值,相当于将顺序号为 2的枚举
元素赋给 workday */
例 袋中有红、黄、白、蓝、黑五种颜色的球。每次从袋
中取出 3个球,问得到三种不同颜色的球的可能取法,
输出每种组合的三种颜色。
main( )
{ enum color {red,yellow,blue,white,black};
enum color i,j,k,pri;
int n=0,loop;
for (i=red; i<= black; i++)
for (j=red; j<= black; j++)
if (i!=j)
{ for (k=red; k<= black; k++)
if ((k!=i) && (k!=j))
{ n=n+1;
printf(“%-4d”,n);
for (loop=1; loop<=3; loop++)
{ switch(loop)
{ case1,pri=i; break;
case2,pri=j; break;
case3,pri=k; break;
}
switch(pri)
{ case red,printf(%-10s”,”red”); break;
case yellow:printf(%-10s”,”yellow”); break;
case blue,printf(%-10s”,”blue”); break;
case white,printf(%-10s”,”white”); break;
case black,printf(%-10s”,”black”); break;
default,break;
}
}
printf(“\n”);
}
}
printf(“\n total:%5d\n”,n);
}
运行结果,
1 red yellow blue
2 red yellow white
3 red yellow black
4 red blue yellow
5 red blue white
6 red blue black
7,,,