一、概述
C语言允许用户自己指定这样一种数据结构,它称 为结构体(structure)。它相当于其他高级语言中的“记录”。
声明一个结构体类型的一般形式为:
struct 结构体名
{成员表列};
“结构体名”用作结构体类型的标志,它又称“结构体标记”(structure tag)。对各成员都应 进行类型声明,即
类型名 成员名;
也可以把“成员表列”(member list)称为“域表”(field list)。每一个成员也称为结构体中 的一个域。成员名命名规则与变量名相同。
二、定义结构体类型变量的方法
1、先声明结构体类型再定义变量名
例如:
struct student (结构体类型名) student1,student2;(两个各为结构体变量名)
2、在声明类型的同时定义变量
此形式的定义的一般形式为:
struct 结构体名
{
成员表列
}变量名表列;
3、直接定义结构体类型变量
其一般形式为:
struct
{
成员表列
}变量名表列;
即不出现结构体名。
关于结构体类型,有几点要说明:
(1)类型与变量是不同的概念,不要混同。只能对变量赋值、存取或运算,而不能对
一个类型赋值、存取或运算。在编译时,对类型是不分配空间的,只对变量分配空间。
(2)对结构体中的成员(即“域”),可以单独使用,它的作用与地位相当于普通变量。 关于对成员的引用方法见11.3节。
(3)成员也可以是一个结构体变量。
(4)成员名可以与程序中的变量名相同,二者不代表同一对象。
三、结构体变量的引用
在定义了结构体变量以后,当然可以引用这个变量。但应遵守以下规则:
(1)不能将一个结构体变量作为一个整体进行输入和输出。
只能对结构体变量中的各个成员分别进行输入和输出。引用结构体变量中成员的方式为:
结构体变量名.成员名
(2)如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到 最低的一级的成员。只能对最低级的成员进行赋值或存取以及运算。
(3)对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。
(4)可以引用结构体变量成员的地址,也可以引用结构体变量的地址。
四、结构体变量的初始化
和其他类型变量一样,对结构体变量可以在定义时指定初始值。
五、结构体数组
1、定义结构体数组
和定义结构体变量的方法相仿,只需说明其为数组即可。
2、结构体数组的初始化
与其他类型的数组一样,对结构体数组可以初始化。
六、指向结构体类型数据的指针
1、指向结构体变量的指针
为了使用方便和使之直 见,可以把(*p).num改用 p->num来代替,它表示p所指向的结构体变量中的num成员。同样,(*p).name等价于p->name。也就是说,以下 3种形式等价:
①结构体变量.成员名
②(*p).成员名
③p->成员名
其中->称为指向运算符。
2、指向结构体数组的指针
已经介绍过可以使用指向数组或数组元素的指针和指针变量,同样,对结构体数组及其元素也可以用指针或指针变量来指向。
3、用结构体变量和指向结构体的指针作为函数参数
将一个结构体变量的值传递给另一个函数,有3个方法:
(1)用结构体变量的成员作参数。例如,用stu[1].num或stu[2].name作函数实 参,将实参值传给形参。用法和用普通变量作实参是一样的,属于“值传递”方式。应当注意实参与形参的类型保持一致。
(2)用结构体变量作实参。用结构体变量作实参时,采取的也是“值传递”的方式,将结构体变量所占的内存单元的内容全部顺序传递给形参,形参也必须是同类型的结构体变量。
(3)用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给 形参。
七、用指针处理链表
1、链表概述
链表是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构。我们知道,用数组存放数据时,必须事先定义固定的长度( 即元素个数)
链表有一个“头指针 ”变量,图中以head表示,它存放一个地址,该地址指向一个元素。链表中每一个元素称为“结点”,每个结点都应包括两个部分:用户需要用的实际数据和下一个结点的地址 。
2、简单链表
以下通过一个例子来说明如何建立和输出一个简单链表:
3、处理动态链表所需的函数
(1)、malloc函数
其函数原型为
void *malloc(unsigned int size);
其作用是在内存的动态存储区中分配一个长度为size的连续空间。此函数的值(即“返回值”)是一个指向分配域起始地址的指针(类型为void)。 如果此函数未能成功地 执行(例如内存空间不足),则返回空指针(NULL)。
(2)、calloc函数
其函数原型为
void *calloc(unsigned n,unsigned size);
其作用是在内存的存储区中分配n个长度为size的连续空间。函数返回一个指向分配域起始地址的指针;如果分配不成功,返回NULL。
用calloc函数可以为一维数组开辟动态存储 ,n为数组元素个数,每个 素长度 为size。
(3)、free函数
其函数原型为
void free(void *p);
其作用是释放由p指向的内存区,使这部分内存区能被其他变量使用。p是最近一次调用calloc或malloc函数时返回的值。free函数无返回值。
4、建立动态链表
所谓建立动态链表是指在程序执行过程中从无到有地建立起一个链表,即一个一个
地开辟结点和输入各结点数据,并建立起前后相链的关系。
例如:写一个函数建立一个有3名学生数据的单向动态链表。
5、输出链表
将链表中各结点的数据依次输出。这个问题比较容易处理。首先要知道链表第一个结点的地址,也就是要知道head的值。然后 设一个指针变量p,先指向第一个结点,输出p所指的结点,然后使p后移一个结点,再输出,直到链表的尾结点。
6、对链表的删除操作
从一个动态链表中删去一个结点,并不是真正从内存中把它抹掉,而是把它从链表中分离开来,只要撤销原来的链接关系即可。
7、对链表的插入操作
对链表的插入是指将一个节点插入到一个已有的链表中。
八、共用体
1、共用体的概念
种使几个不同的变量共占同一段内存的结构,称为“共用体”类型的结构。
定义共用体类型变量的一般形式为:
union 共用体名
{成员表列
}变量表列;
例如:
union data
{int i;
char ch;
float f;
}a,b,c;
也可以将类型声明与变量定义分开:
union data
{int i;
char ch;
float f;
};
union data a,b,c;
2、共用体变量的引用方式
只有先定义了共用体变量才能引用它,而且不能引用共用体变量,而只能引用共用体变量中的成员。例如,前面定义了a、b、c为共用体变量,下面的引用方式是正确的:
a.i (引用共用体变量中的整型变量i
a.ch (引用共用体变量中的字符变量ch)
a.f (引用共用体变量中的实型变量f)
不能只引用共用体变量。
3、共用体类型数据的特点
在使用共用体类型数据时要注意以下一些特点:
(1)同一个内存段可以用来存放几种不同类型的成员,但在每一瞬时只能存放其中 一种,而不是同时存放几种。也就是说,每一瞬时只有一个成员起作用,其他的成员不起 作用,即不是同时都存在和起作用。
(2)共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原 有的成员就失去作用。
(3)共用体变量的地址和它的各成员的地址都是同一地址。
(4)不能对共用体变量名赋值,也不能企图引用变量名来得到一个值,又不能在定义 共用体变量时对它初始化。
(5)共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。
九、枚举类型
枚举类型是ANSIC新标准所增加的。
如果一个变量只有几种可能的值,则可以定 为枚举类型。所谓“枚举”是指将变量 的值一一列举出来,变量的值只限于列举出来的值的范围内。 声明枚举类型 enum开头。
说明:
(1)在C编译中,对枚举元素按常量处理,故称枚举常量。
(2)枚举元素作为常量,它们是有值的,C语言编译按定义时的顺序使它们的值为0
1,2… 在上面定义中,sun的值为0,mon的值为1……sat的值为6。
(3)枚举值可以用来作判断比较。
(4)一个整数不能直接赋给一个枚举变量。
十、用typedef定义类型
除了可以直接使用C提供的标准类型名(如int、char、flo at、double、long等)和自己声明的结构体、共用体、指针、枚举类型外,还可以用typede 声明新的类型名来代替已有 的类型名。
归纳起来,声明一 的类型名的方法是:
①先按定义变量的方法写出定义体(如:int i;)。
②将变量名换成新类型名(例如:将i换成COUNT)。
③在最前面加typedef(例如:typedef int COUNT)。
④然后可以用新类型名去定义变量。
说明:
(1)用typedef可以声明各种类型名,但不能用来定义变量。用typedef可以声明数 组类型、字符串类型,使用比较方便。
(2)用typedef只是对已经存在的类型增加一个类型名,而没有创造新的类型。
(3)typedef与#define有相似之处,例如:
typedef int COUNT;
和
#define COUNT int
的作用都是用COUNT代表int。但事实上,它们二者是不同的。#define是在预编译时 处理的,它只能作简单的字符串替换,而typedef是在编译时处理的。实际上它并不是作 简单的字符串替换,
(4)当不同源文件中用到同一类型数据(尤其是像数组、指针、结构体、共用体等类型 数据)时,常用typedef声明一些数据类型,把它们单独放在一个文件中,然后在需要用到 它们的文件中用#include命令把它们包含进来。
(5)使用typedef有利于程序的通用与移植。有时程序会依赖于硬件特性,用 typedef便于移植。