本章导读结构体、联合体、枚举类型都是用户自己定义的数据类型,
这些类型的数据是用户根据实际需要来组织的。结构体和联合体都是构造类型的数据,枚举类型是基本类型的数据。
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本书目录第 7章 结构体、联合体和枚举类型本章主要知识点
( 1)结构体类型数据的定义,结构变量的说明及引用方法结构指针的定义、使用以及结构指针在 C程序中的应用 ——
链表的建立、输出、删除与插入等操作
( 2)联合体类型数据的定义,联合变量的说明及引用方法
( 3)枚举类型数据的定义,枚举变量的说明及引用方法
( 4)了解自定义类型的概念和类型定义方法及应用第 7章 结构体、联合体和枚举类型
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章导读
7.1 结构体
7.2 联合体
7.3 枚举类型
7.4 自定义类型
7.5 综合实训
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
7.1 结构体
7.1.1 结构体与结构变量
7.1.2 结构成员的引用
7.1.3 结构数组
7.1.4 结构指针与链表
7.1.1 结构体与结构变量
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
“结构体,是一种构造类型,是由 数目固定,类型相同或不同的若干 有序 变量组成的集合。组成结构体的每个数据都称为结构体的,成员,,或称,分量,。
返回本节目录
1.结构体类型的声明
2.结构变量的定义
3.结构体类型与结构变量
1.结构体类型的声明
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.1.1目录声明一个结构体类型的一般形式为:
struct <结构体名(也称为结构体标记) >
{ 成员表列(也称为域表)
};
应注意在 括号后的分号是不可少的 。成员表列由若干个成员组成,每个成员都是该结构体的一个组成部分。对每个成员也必须作类型说明,其形式为:
<类型说明符 > <成员名 >;
成员名的命名应符合 C语言标识符的书写规定,结构体成员名可与程序中其它变量同名,互不干扰。
2.结构变量的定义
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.1.1目录对于已经声明的结构体类型,就可有对应于该类型的,结构类型变量,,
简称为,结构变量,。定义结构变量有以下三种方法:
(1)先声明结构体类型,再定义结构变量即在先前声明的结构体类型后加上以下形式:
struct <结构体名 > <结构变量表列 >;
(2)在声明结构体类型的同时定义结构变量即被定义的结构变量直接在结构体类型声明的,}”后给出。一般形式为:
struct <结构体名 >
{ 〈 成员表列 〉
}〈 结构变量表列 >;
(3)直接定义结构变量即省略结构体名。一般形式为:
struct
{ <成员表列 >
}<结构变量表列 >;
3.结构体类型与结构变量
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.1.1目录结构体类型与结构变量的最大区别在于,结构变量占有一定的内存空间,而 结构体类型只是一种数据类型的结构描述,并不占用内存空间 。
struct box
{ float length;
float width;
float height;
};
它表明 struct box结构体类型由大括号中所列的一些数据项组成,共需占用 4x3=12个字节。
在此之后,若进行结构变量的定义如,struct box box1;
表明 box1为 struct box结构体类型变量,它占用了 12个字节的内存单元。
7.1.2 结构成员的引用
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录对结构变量的访问是通过对结构变量各个成员的访问来进行的,
结构变量成员描述为,<结构变量名 >.<成员名 >
在引用中应遵循以下原则:
( 1)如果成员本身又是一个结构体类型时,则必须 逐级 找到最低一级的成员才能使用。
( 2)对成员变量的使用与普通变量完全相同,可根据其类型进行相应的运算。
( 3)可以引用成员的地址,也可以引用结构体变量的地址。
( 4)允许将一个结构变量直接赋值给另一个具有相同结构的结构变量。
【 例 7.1】
例 7.1( 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.1.2目录
【 例 7.1】 利用结构体对三名学生的学号,姓名,性别,成绩进行输入与输出 。
程序名为 l7_1.cpp。
#include "stdio.h"
struct stu
{ long int num;
char name[20];
char sex;
float score;
}student1,student2={960002,"Zhang hong li",'W',98},student3;/*对 student2初始化 */
main()
{ student1.num=960001; /*对 student1各成员赋值 */
scanf("%s",student1.name);
student1.sex='M';
student1.score=65;
student3=student1; /*对 student3直接赋值 */
例 7.1( 2接上页)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.1.2目录
printf("\n%ld\t%20s\t%c\t%f",student1.num,student1.name,student1.sex,
student1.score);
printf("\n%ld\t%20s\t%c\t%f",student2.num,student2.name,student2.sex,
student2.score);
printf("\n%ld\t%20s\t%c\t%f",student3.num,student3.name,student3.sex,
student3.score);
}
运行情况如下:
输入,Lilin< CR >
960001 Lilin M 65
960002 Zhang hong li W 98
960001 Lilin M 65
程序演示
[例 7.1]程序演示返回例题 返回 7.1.2目录
7.1.3 结构数组
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录数组元素是结构体类型数据,这时的数组就是结构数组。
1.结构数组的定义
2,结构数组的初始化
【 例 7.2】
1.结构数组的定义
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.1.3目录结构数组的定义方法和结构变量相似,只需说明它为数组类型即可。
例如:
struct stu
{ int num;
char name[20];
char sex;
float score;
};
struct stu student[3];
也可以直接定义一个结构数组或省略结构体名。
2.结构数组的初始化
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.1.3目录对结构数组可以进行初始化,它的作用在于把成批的数据传递给结构数组中的各个元素。
初始化的一般形式为:
struct <结构体名 > <结构数组 >[n]={<初始表列 >};
其中,n为元素的个数。在初始表列中,以一个元素内容为单位,
用一对,{}”括起来,各元素之间用“,,分隔。
当对数组中的全部元素初始化时,也可将,[ ]”中的数组元素个数省略。在编译时,系统会根据给出初值的结构体常量的个数来确定数组元素的个数。
数组的初始化也可以先声明结构体类型,然后再定义数组为该结构体类型,并在定义数组时初始化。
【 例 7.2】 ( 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.1.3目录
【 例 7.2】 计算学生的平均成绩并统计出不及格的人数 。 程序名为 l7_2.cpp。
#include "stdio.h"
struct stu
{ long int num;
char name[20];
char sex;
float score;
}student[3]={{200001,"Li li",'W',99},{200002,"Wang hai",'M',85},
{200003,"Liu ying",'W',50}};
main()
{ int i,n;
float average,sum;
n=0;
sum=0;
【 例 7.2】 ( 2上接 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.1.3目录
for(i=0;i<3;i++)
{ sum+=student[i].score;
if(student[i].score<60) n+=1;
}
printf("sum=%f\n",sum);
average=sum/3;
printf("average=%f\ncount=%d\n",average,n);
}
运行情况如下:
sum=234.000000
average=78.000000
count=1.
程序演示
【 例 7.2】 程序演示返回例题 返回 7.1.3目录
7.1.4 结构指针与链表
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
1.结构指针
2.链表
1.结构指针
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.1.4目录我们把指向结构体的指针称为结构指针,它是一个指针变量。
结构指针变量说明的一般形式为:
struct <结构体名 > *<结构指针变量名 >;
这样说明的含义是:一规定了指针的数据特性;二为结构指针本身分配了一定的内存空间。
结构指针变量 必须要先赋值后才能使用,赋的值应是一个地址值。
有了结构指针变量,就能更方便地访问结构变量的各个成员。
其访问的一般形式为:
<(*结构指针变量 )>.<成员名 >
或为:
<结构指针变量 >-><成员名 >
1.结构指针
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.1.4目录在结构指针的使用中可分为以下几种情况:
(3)结构指针作函数参数
(1)指向结构变量
(2)指向结构数组
(1)指向结构变量
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 1目录当使用结构指针指向一个结构变量时,指针变量中的值就是所指向的结构变量的首地址。
这三种用于表示结构成员的形式是完全等效的。
①结构变量,成员名
② (*结构指针变量 ).成员名
③结构指针变量 ->成员名请注意分析下面几种运算:
s->n 得到 s指向的结构变量中的成员 n的值
s->n++ 得到 s指向的结构变量中的成员 n的值,用完该值后使它加 1
++s->n 得到 s指向的结构变量中的成员 n的值使之加 1
【 例 7.3】
【 例 7.3】 ( 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (1)
【 例 7.3】 通过结构指针引用结构体成员 。 程序名为 l7_3.cpp。
#include "stdio.h"
struct stu
{ int num;
char name[20];
char sex;
float score;
}student1={102,"Zhang ping",'M',78.5},*s;
main()
{ s=&student1; /*给结构指针变量赋值 */
printf("Number=%d\tName=%s\t",student1.num,student1.name);
printf("Sex=%c\tScore=%f\n",student1.sex,student1.score);
printf("Number=%d\tName=%s\t",(*s).num,(*s).name);
printf("Sex=%c\tScore=%f\n",(*s).sex,(*s).score);
printf("Number=%d\tName=%s\t",s->num,s->name);
printf("Sex=%c\tScore=%f\n",s->sex,s->score);
}
【 例 7.3】 ( 2上接 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (1)
运行情况如下:
Number=102 Name=Zhang ping Sex=M Score=78.500000
Number=102 Name=Zhang ping Sex=M Score=78.500000
Number=102 Name=Zhang ping Sex=M Score=78.500000
程序演示
【 例 7.3】 程序演示返回例题 返回 (1)
(2)指向结构数组
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 1目录当结构指针指向一个结构数组时,该指针变量的值是整个结构数组的首地址。
当然结构指针也可以指向结构数组中的某个元素,这时指针变量的值是该结构数组元素的首地址。
设 s为指向结构数组的指针变量,则 s也指向该结构数组的 0号元素,s+1指向 1号元素,s+i则指向 i号元素。
【 例 7.4】
【 例 7.4】 (1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (2)
【 例 7.4】 用指针变量输出结构数组 。 程序名为 l7_4.cpp。
#include "stdio.h"
struct stu
{ long int num;
char name[20];
char sex;
float score;
}student[3]={{200001,"Li li",'W',99},{200002,"Wang hai",'M',85},
{200003,"Liuying ",'W',50}};
main()
{ struct stu *s;
printf("Num\tName\t\tSex\tScore\t\n");
for(s=student;s<student+3;s++)
printf("%ld\t%-10s\t%c\t%f\t\n",s->num,s->name,s->sex,s->score);
}
【 例 7.4】 (2上接 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (2)
运行情况如下:
Num Name Sex Score
200001 Li li W 99.000000
200002 Wang hai M 85.000000
200003 Liuying W 50.000000.
程序演示
【 例 7.4】 程序演示返回例题 返回 (2)
(3)结构指针作函数参数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

使用结构指针,即用指向结构变量(或数组)的结构指针作函数参数进行传送,这时由实参向形参传递的是地址,属于,地址传递,方式,减少了时间和空间上的开销。
【 例 7.5】
返回 1目录
【 例 7.5】 ( 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (3)
【 例 7.5】 用结构指针变量作函数参数编程,计算一组学生的平均成绩并统计出不及格人数 。 程序名为 l7_5.cpp。
#include "stdio.h"
struct stu
{ long int num;
char name[20];
char sex;
float score;
}student[3]={{200001,"Li li",'W',99},{200002,"Wang hai",'M',85},
{200003,"Liuying ",'W',50}};
void average(struct stu *ps)
{ int n=0,i;
float ave,s=0;
【 例 7.5】 ( 2上接 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (3)
for(i=0;i<3;i++,ps++)
{ s+=ps->score;
if(ps->score<60) n+=1;
}
printf("s=%f\n",s);
ave=s/3;
printf("average=%f\ncount=%d\n",ave,n);
}
main()
{ struct stu *s;
s=student;
average(s);
}
运行情况如下:
s=234.000000
average=78.000000
count=1.
程序演示
【 例 7.5】 程序演示返回例题 返回 (3)
2.链表
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.1.4目录
(1)动态存储分配函数
(2)链表的使用
(1)动态存储分配函数
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 2目录
① 分配内存空间函数 malloc
② 分配内存空间函数 calloc
③ 释放内存空间函数 free
【 例 7.6】
① 分配内存空间函数 malloc
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (1)目录
① 分配内存空间函数 malloc
调用形式,(类型说明符 *) malloc (size)
功能:在内存的动态存储区中分配一块长度为,size”字节的连续空间。函数的返回值为该空间的首地址;若此函数未能成功的执行,则返回的值为 0。
,类型说明符,表示把该区域用于何种数据类型。 (类型说明符
*)表示把返回值强制转换为该类型指针。,size”是一个无符号数。
例如,pc=(char *) malloc (100);表示分配 100个字节的内存空间,并强制转换为字符数组类型,函数的返回值为指向该字符数组的指针,把该指针赋予指针变量 pc。
② 分配内存空间函数 calloc
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (1)目录
② 分配内存空间函数 calloc
调用形式,(类型说明符 *) calloc(n,size)
功能:在内存动态存储区中分配 n块长度为,size”字节的连续空间。
函数的返回值为该空间的首地址;若此函数未能成功的执行,则返回的值为 0。
(类型说明符 *)用于强制类型转换。 calloc函数与 malloc函数的区别仅在于一次可以分配一块还是 n块区域。
例如:语句 ps=(struct stu*) calloc(2,sizeof(struct stu));中的函数 sizeof(struct stu)是求 struct stu结构体类型的长度。因此该语句的意思是:按照 struct stu的长度分配 2块连续区域,强制转换为 struct stu类型,并把其首地址赋予指针变量 ps。
③ 释放内存空间函数 free
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (1)目录
③ 释放内存空间函数 free
调用形式,free (void*ptr);
功能:释放 ptr所指向的内存空间,ptr指向被释放区域的首地址,被释放区应是由 malloc或 calloc函数所分配的空间。 ptr是一个无类型的指针变量。
【 例 7.6】 ( 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
【 例 7.6】 分配一块区域,输入一个学生数据 。 程序名为 l7_6.cpp。
#include "stdio.h"
#include "malloc.h"
#include "string.h"
main()
{ struct stu
{ int num;
char name[20];
char sex;
float score;
}*s;
s=(struct stu*)malloc(sizeof(struct stu));
【 例 7.6】 ( 2上接 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (1)目录
s->num=102;
strcpy(s->name,"Zhang ping");
s->sex='M';
s->score=62.5;
printf("Number=%d\nName=%s\n",s->num,s->name);
printf("Sex=%c\nScore=%f\n",s->sex,s->score);
free(s);
}
运行情况如下:
Num=102
Name=Zhang ping
Sex=M
Score=62.500000
程序演示
【 例 7.6】 程序演示返回例题 返回 (1)目录
(2)链表的使用
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 2目录链表是一种常见的、重要的数据结构,它采用 动态 的分配办法为一个结构体分配内存空间。
一方面 需要时就分配 一块空间用来存放,从而节约了宝贵的内存资源;且便于删除与加入。
另一方面,在动态分配时,每个结点之间可以是 不连续 的 (结点内是连续的 ),结点之间的联系是通过 指针 来实现的,即在结点结构中定义一个成员项用来存放下一结点的首地址,这个用于存放地址的成员,常把它称为指针域。可在第一个结点的指针域内存入第二个结点的首地址,在第二个结点的指针域内又存放第三个结点的首地址,如此串连下去直到最后一个结点。最后一个结点因无后续结点连接,其指针域可赋为 NULL。
这样一种连接方式,如同一条一环接一环的链子,在数据结构中称之为,链表,。
(2)链表的使用
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 2目录例如,一个存放学生学号和成绩的结点可以定义为以下结构:
struct stu
{ int num;
int score;
struct stu *next;
};
在该结构体中前两个成员项组成数据域,最后一个成员项 next构成指针域,它是一个指向 struct stu类型的结构指针变量。
对链表的基本操作主要有:
① 建立链表 ② 链表的输出
③ 链表的删除操作 ④ 链表的插入操作
【 例 7.11】
① 建立链表 ( 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

建立链表就是指从无到有地建立起一个链表,即一个个地输入各结点数据,并建立起前后相链的关系。
【 例 7.7】 编写一个建立单向链表的函数,存放学生数据。
函数 create可编写如下:
#include "stdio.h"
#include "malloc.h"
#define NULL 0 /*令 NULL为 0,用它表示空地址 */
#define LEN sizeof (struct stu)/*LEN代表 struct stu结构体类型数据的长度
*/
struct stu
{ long int num;
float score;
struct stu *next;
}; 返回 (2)目录
① 建立链表 ( 2上接 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (2)目录
int n;
struct stu *creat() /*此函数带回一个指向链表头的指针 */
{ struct stu *head,*p1,*p2;
n=0; /*n为结点的个数 */
p1=p2=(struct stu *)malloc(LEN); /*开辟一个新单元 */
scanf("%ld,%f",&p1->num,&p1->score);
head=NULL;
while(p1->num!=0)
{ n=n+1;
if (n==1)head=p1;
else p2->next=p1;
① 建立链表( 3上接 2)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (2)目录
p2=p1;
p1=( struct stu *)malloc(LEN);
scanf("%ld,%f",&p1->num,&p1->score);
}
p2->next=NULL;
return(head); /*返回链表的头地址 */
}
图 7-7,图 7-8,图 7-9,图 7-10,图 7-11表示出 creat函数的执行过程。
图 7-7
返回图 7-8
返回图 7-9(a)
返回图 7-9(b)
返回图 7-9(c)
返回图 7-10(a)
返回图 7-10(b)
返回图 7-10(c)
返回图 7-11
返回
② 链表的输出
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (2)目录将链表中各结点的数据依次输出,首先要知道链表头元素的地址。设一个指针变量 p,指向第一个结点,待输出 p所指的结点数据后,使 p后移一个结点再输出,直至链表的尾结点止。程序执行过程可见 图 7-12所示。
【 例 7.8】 写一个函数,输出链表中所有结点。
void print(head) /*由实参即将已有的链表的头指针传给被调函数 */
struct stu *head;
{ struct student *p;
printf("\n Now,these %d records are:\n",n);
p=head; /* p指向头结点 */
while(p!=NULL)
{ printf("%ld,%f\n",p->num,p->score); /*输出所指结点的数据域 */
p=p->next; /*使 p指向下一个结点 */
}
}
图 7-12
返回
③ 链表的删除操作
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (2)目录从一个链表中删除一个结点,并不是真正从内存中把它抹去,而是把它从链表中分离开来,可以通过改变链表的链接关系完成。
分析:设两个指针变量 p1和 p2,先使 p1指向第一个结点。删除一个结点有两种情况:
一种情况是要删除结点是第一个结点,此时只需使 head指向第二个结点即可,即 head=p1->next,其过程如 图 7-13所示。
另一种情况是被删除结点不是第一个结点,可使被删除结点的前一结点指向被删结点的后一结点,即 p2->next=p1->next,其过程如图 7-14所示。
【 例 7.9】 写一个函数,删除链表中的指定结点,以指定的学号作为删除结点的标志。函数 dele编写如下:
struct stu * dele(struct stu *head,long int num)
{ struct stu *p1,*p2;
③ 链表的删除操作
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

if(head==NULL) /*如为空表,输出提示信息 */
{ printf("\nempty list!\n");
goto end;}
p1=head;
while (p1->num!=num && p1->next!=NULL) /*当不是要删除的结点,而且也不是最后一个结点时,继续循环 */
{ p2=p1;p1=p1->next; /*后移一个结点 */
}
if(p1->num==num) /*找到要删除的结点 */
{ if(p1==head)head=p1->next; /*为第一结点 head指向第二结点 */
else p2->next=p1->next;
/*不是第一个结点,使要删除结点从链表中脱离 */
返回 (2)目录
③ 链表的删除操作
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

n=n-1;
free(p1);
}
else
printf("The node not been foud!\n");
end,
return head; /*返回 head值 */
}
返回 (2)目录图 7-13
返回图 7-14(a)
返回图 7-14(b)
返回图 7-14(c)
返回
④ 链表的插入操作
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

在一个链表的指定位置插入结点,首先要求链表本身必须是已按某种规律排好序的。按照排序的规律确定好新结点在链表中的位置,
并将其连入链表中即可。分析:设被插入结点的指针为 p0,p1指向第一个结点。可在四种不同情况下插入:
第一种情况是原链表是空链表,只需使 head指向被插入结点即可,
见 图 7-15(a)。
第二种情况是被插入结点值最小,则应插入到第一个结点之前。
这种情况下使 head指向被插入结点,被插入结点的指针域指向原来的第一个结点即可,即用 p0->next=p1;head=p0;完成,见 图 7-15(b)。
第三种情况是在其它位置插入,见 图 7-15(c)。这种情况下,使插入位置的前一结点的指针域指向被插入结点,使被插入结点的指针域指向插入位置的后一结点,即用 p0->next=p1;p2->next=p0;来完成。
返回 (2)目录
④ 链表的插入操作
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

最后一种情况是在表末插入,见 图 7-15(d)。这种情况下使原链表中的末结点指针域指向被插入结点,被插入结点指针域置为 NULL。即用 p1-
>next=p0p0->next=NULL;来完成。
【 例 7.10】 写一个函数,在学生数据链表中,按学号顺序插入一个结点。
struct stu * insert(struct stu *head,struct stu *stud)
{ struct stu *p0,*p1,*p2;
p1=head; /*指向第一个结点 */
p0=stud; /*指向要插入的结点 */
if(head==NULL) /*空表插入 */
{ head=p0;
p0->next=NULL;
} /*将 p0指向的结点作第一个结点 */
返回 (2)目录
④ 链表的插入操作
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

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;
}
返回 (2)目录
④ 链表的插入操作
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

else
{ p1->next=p0;
p0->next=NULL;
} /*在表末插入 */
}
n=n+1;
return (head);
}
返回 (2)目录图 7-15(a)
返回图 7-15(b)
返回图 7-15(c)
返回图 7-15(d)
返回
【 例 7.11】
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 (2)目录
【 例 7.11】 将以上建立链表,输出链表,删除结点,插入结点的函数组织在一个程序中,用 main 函数作主调函数 。 程序名为
l7_7891011.cpp。
main函数内容如下,( 其位置在以上各函数之后 )
#include "stdio.h"
main()
{ struct stu * head,stud;
long int num;
printf("input records:\n ");
head=creat(); /*调用 creat函数建立链表并把头指针返回给 head*/
print(head); /*调用 print函数输出链表 */
printf("Input the deleted number,");
scanf(“%ld”,&num); /*输入待删结点的学号 */
head=dele(head,num); /*调用 dele函数删除一个结点 */
【 例 7.11】
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

print(head); /*调用 print函数输出链表 */
printf("Input the inserted number and score,");
scanf("%ld,%f",&stud.num,&stud.score); /*输入待插入结点的数据域值 */
head=insert(head,&stu); /*调用 insert函数插入 pnum所指的结点 */
print(head); /*再次调用 print函数输出链表 */
}
运行情况如下:
input records:
输入,96001,85< CR >
96002,75.2< CR >
96005,62< CR >
0,0< CR >
返回 (2)目录
【 例 7.11】
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

Now,these 3 records are:
96001,85.000000
96002,75.199997
96005,62.000000
Input the deleted number,输入,96002< CR >
Now,these 2 records are:
96001,85.000000
96005,62.000000
Input the insert number and score,输入,96004,78< CR >
Now,these 3 records are:
96001,85.000000
96004,78.000000
96005,62.000000
程序演示返回 (2)目录
【 例 7.11】 程序演示返回例题 返回本节目录
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
7.2 联合体
7.2.1 联合体和联合变量
7.2.2 联合体的引用及特点在 C语言中,把这种将几种不同类型的变量存放在同一段内存单元中的结构称为“联合体”,也称为“共用体”。
“联合体”与“结构体”有一些相似之处,但两者有本质上的不同。
在结构体中各成员有各自的内存空间,一个结构变量的总长度是各成员长度之和;而在联合体中,各成员共享一段内存空间,一个联合变量的长度等于各成员中最长的长度。
【 例 7.12】
7.2.1 联合体和联合变量
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
1.联合体类型的声明
2.联合变量的定义
1.联合体类型的声明
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.2.1目录声明一个联合体类型的一般形式为:
union <联合体名 >
{ <成员表列 >
};
成员表列中含有若干成员,成员的一般形式为:
<类型说明符 > <成员名 >;
成员名的命名应符合标识符的规定。
例如:
union perdata
{ int class;
char office[10];
};
2.联合变量的定义
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.2.1目录联合体类型声明之后,就可以进行联合变量的定义,被定义为
union perdata类型的变量,可以存放整型量 class或字符型数组 office。
联合变量的定义和结构变量的定义方式相似,也有三种形式。
以 union perdata联合体类型为例,定义如下:
(1)先声明再定义
(2)声明的同时定义
(3)直接定义
7.2.2 联合体的引用及特点
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
1.引用
2.特点
1.引用
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.2.2目录对联合变量的赋值、使用都只能针对联合变量的成员进行。联合变量的成员表示为:
<联合变量名 >.<成员名 >
例如,a被定义为 union perdata类型的变量之后,可使用
a.class,a.office成员。
2.特点
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

在使用联合体类型数据时要注意它具有以下一些特点:
( 1)一个联合变量,每次只能赋予一个成员值。换句话说,一个联合变量的值就是联合变量的某一个成员值。
( 2)联合变量中起作用的成员是最后一次存放的成员。
( 3)不允许只用联合变量名作赋值或其它操作,如 a=1;或 b=a;均为错。
( 4)不允许对联合变量作初始化赋值,赋值只能在程序中进行。
( 5)不能把联合变量作为函数参数,也不能使函数带回联合变量,
但可以使用指向联合变量的指针。
( 6)联合体类型可以出现在结构体类型定义中,也可以定义联合体数组。结构体也可以出现在联合体类型定义中,数组也可以作为联合体的成员。
返回 7.2.2目录
【 例 7.12】
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
【 例 7.12】 编写程序使用联合体类型数据来保存如下表格 ( 表 7-1) 中的数据,
调试验证是否可行 。 程序名为 l7_12.cpp。
#include "stdio.h"
main()
{ union t
{ char *name;
int age;
int income;
};
union t list;
printf("%d\n",sizeof(union t*)); /*输出联合体类型长度 */
list.name="Zhang hai"; /*第一次赋值 */
printf("%s\t",list.name);
list.age=20; /*第二次赋值 */
printf("%d\t",list.age);
list.income=2500; /*第三次赋值 */
printf("%d\n",list.income);
printf("%s\t%d\t%d\n",list.name,list.age,list.income);/*输出各成员值 */
}
程序演示
【 例 7.12】 程序演示返回例题 返回本节目录
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
7.3 枚举类型
7.3.1 枚举类型及变量的定义
7.3.2 枚举元素的引用
C语言提供了一种“枚举”类型,在枚举类型的定义中 列举出所有可能的取值,被说明为该“枚举”类型的变量取值不能超过定义中列举出来的常量的范围。应该说明的是,枚举类型是一种 基本数据类型,而不是一种构造类型,因为它不能再分解为任何基本类型。
【 例 7.14】
7.3.1 枚举类型及变量的定义
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
1.枚举类型的声明
2.枚举变量的定义
1.枚举类型的声明
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回 7.3.1目录枚举类型声明的一般形式为:
enum <枚举类型名 >
{ <枚举值表 >
};
在枚举值表中应罗列出所有可用值,用,,”分隔,这些值也称为枚举元素或枚举常量。枚举元素是用户自己定义的标识符,并不自动代表什么含义。
例如:
enum weekday
{ sun,mon,tue,wed,thu,fri,sat
};
该枚举名为 weekday,枚举值共有 7个,即一周中的七天。凡被声明为 enum
weekday类型的变量取值只能是七天中的某一天。其中的 sun不一定就代表
,星期天,,用什么标识符代表什么含义,完全由程序员自己决定,并在程序中做相应处理。
2.枚举变量的定义
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

枚举变量也有多种不同的定义方式。现有变量 a,b,c需被定义为上述的 enum weekday类型的变量,可采用下述任一种方式:
(1)先声明后定义
enum weekday
{,.....
};
enum weekday a,b,c;
(2)声明的同时定义
enum weekday
{,....
}a,b,c;
(3)直接定义
enum
{,.....
}a,b,c;
返回 7.3.1目录
7.3.2 枚举元素的引用
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录枚举类型在使用中有以下规定:
1.枚举元素是常量,不是变量,不能在程序中再对它赋值。
2.枚举元素本身由系统定义了一个表示序号的数值,从 0开始顺序定义为 0,1,2… 。
3.在定义时可以改变枚举元素的值。
4.枚举值可以用来做判断比较。如,if(a>sun)…… 是合法的。
5.只能把枚举元素的值赋予枚举变量,不能把枚举元素的数值直接赋予枚举变量。
6.如一定要把枚举元素的数值赋予枚举变量,则必须用强制类型转换。如,a=(enum weekday)2;其意义是将顺序号为 2的枚举元素赋予枚举变量 a,相当于,a=tue;。
7.还应该说明的是枚举元素不是字符常量也不是字符串常量,使用时不要加单、双引号。
【 例 7.14】 ( 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
【 例 7.14】 有 zhao,wang,zhang,li四人轮流值班,本月有 31天,第一天由 zhang来值班,编写程序做出值班表 。 程序名为 lt7_14.cpp。
#include "stdio.h"
main()
{ enum body
{ zhao,wang,zhang,li
}month[31],j;
int i;
j=zhang;
for(i=1;i<=30;i++)
{ month[i]=j;
j=(enum body)(j+1); /*必须使用强制类型转换 */
if (j>li)
j=zhao;
}
【 例 7.14】 ( 2上接 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
for(i=1;i<=30;i++)
{ switch(month[i])
{ case zhao:printf(" %2d %6s\t",i,"zhao"); break;
case wang:printf(" %2d %6s\t",i,"wang"); break;
case zhang:printf(" %2d %6s\t",i,"zhang"); break;
case li:printf(" %2d %6s\t",i,"li"); break;
default:break;
}
}
printf("\n");
}
程序演示
【 例 7.14】 程序演示返回例题 返回本节目录
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
7.4 自定义类型
1.自定义类型的使用
2.自定义类型的作用
3.有关 typedef的几点说明
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
1.自定义类型的使用
(1)自定义类型的一般形式
typedef <原类型名 > <新类型名 >
其中原类型名中含有定义部分,新类型名一般用大写表示,以便于区别。
(2)自定义一个新类型名的方法
①先按定义变量的方法写出定义体。 (如,int a;)
② 将变量名换成新类型名。(如:将 a换成 INTEGER)
③在最前面加上 typedef。(如,typedef int INTEGER)
至此一个新的类型名就定义好了。
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

2.自定义类型的作用
(1)用 typedef定义数组、指针、结构体等类型将带来很大的方便,不仅使程序书写简单而且使意义更为明确,因而增强了可读性。
例如,typedef char NAME[20];表示 NAME是字符数组类型,数组长度为 20。
我们可用 NAME说明变量,如,NAME a1,a2,s1,s2;
完全等效于,char a1[20],a2[20],s1[20],s2[20];。
定义 STU表示 struct stu结构体类型,然后可用 STU来说明结构变量,
如:
STU body1,body2;
(2)使用 typedef有利于程序的通用和移植。当程序依赖于硬件特性时,
用 typedef便于移植。
返回本节目录
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

3.有关 typedef的几点说明
( 1)用 typedef可以用来定义各种类型名,但不能定义变量。
( 2)用 typedef只是对已有的类型增加一个类型名,并没有创造新的类型。
( 3)在有时也可用宏定义来代替 typedef的功能,但事实上,
二者是不同的。宏定义是在预编译是处理完成的,只是简单的字符串替换;而 typedef则是在编译时完成的,后者更为灵活方便。
返回本节目录
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本章目录
7.5 综合实训
【 例 7.15】
【 例 7.16】
【 例 7.15】 (1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
【 例 7.15】 设有一个教师与学生通用的表格(表 7-2),教师数据有号码、
姓名、职业、教研室四项;学生数据有号码、姓名、职业、班级四项。编写程序输入人员数据,再以表格输出。程序名为 l7_15.cpp。
#include "stdio.h"
struct
{ int num;
char name[10];
char job;
union
{ int classnum;
char office[10];
} depa;
}body[2];
【 例 7.15】 (2上接 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
main()
{ int n,i;
for(i=0;i<2;i++)
{ printf("input num,name,job and department\n");
scanf("%d %s %c",&body[i].num,body[i].name,&body[i].job);
if(body[i].job=='s')
scanf("%d",&body[i].depa.classnum);
else if (body[i].job=='t')
scanf("%s",body[i].depa.office);
else
printf( "input error");
}
printf("num\tname\t\tjob\t department \n");
【 例 7.15】 (3上接 2)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录
for(i=0;i<2;i++)
{ if(body[i].job=='s')
printf("%d\t%s\t%c\t%d\n",body[i].num,body[i].name,body[i].job,
body[i].depa.classnum);
else
printf("%d\t%s\t%c\t%s\n",body[i].num,body[i].name,body[i].job,
body[i].depa.office);
}
}
【 例 7.15】 (4上接 3)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

返回本节目录程序演示运行情况如下:
input num,name,job,and department
输入,9601 zhanghai s 302< CR >
input num,name,job,and department
输入,9603 lixiaoming t jiaowuke < CR >
num name job department
9601 zhanghai s 302
9603 lixiaoming t jiaowuke
【 例 7.15】 程序演示返回例题 返回本节目录
【 例 7.16】 ( 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

【 例 7.16】 口袋中有红、黄、蓝、白、黑五种颜色的棋子若干个,每次从口袋中取出 3个不同颜色的棋子,问可得到多少种不同的取法,打印出每种组合的三种颜色。程序名为 l7_16.cpp。
分析:采用枚举变量来处理,设取出的球为 i,j,k,根据题意,它们分别是
5种颜色的棋子之一,并且 i≠j≠k。可以采用穷举法,看哪一种符合条件。
#include "stdio.h"
main()
{ enum color{red,yellow,blue,white,black}i,j,k,pri;
int n,loop;
n=0;
for(i=red;i<=black;i=(enum color)(i+1))
for(j=red;j<=black; j=(enum color)(j+1))
if(i!=j)
返回本节目录
【 例 7.16】 ( 2上接 1)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

{ for(k=red;k<=black; k=(enum color)(k+1))
if((k!=i)&&(k!=j))
{ n=n+1;
printf("%-4d",n);
for(loop=1;loop<=3;loop++)
{ switch(loop)
{ case 1:pri=i; break;
case 2:pri=j; break;
case 3:pri=k; break;
default:break;
}
返回本节目录
【 例 7.16】 ( 3上接 2)
《C
语言程序设计
,(V
isu
al
C+
+
6.
0
环境

程序演示
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("\ntotal:%5d\n",n);
}
返回本节目录
【 例 7.16】 程序演示返回例题 返回本节目录