分类: C/C++
2015-05-13 09:23:24
一、定义和使用结构体变量
1、 自己建立结构体类型
结构体:C语言允许用户自己建立由不同类型数据组成的组合型的数据结构。在其他一些高级语言中称为“记录”。
声明一个结构体类型的一般形式为
struct 结构体名
{成员表列};
花括号内是该结构体所包含的子项,称为结构体的成员。对各成员都应进行类
型声明,即:
类型名 成员名;
“成员表列“也称为“域表”(field list),每一个成员是结构体中的一个域。成员名命名规则与变量名相同。
2、 定义结构体类型变量
为了能在程序中使用结构体类型的数据,应当定义结构体类型的变量,并在其中存放具体的数据。可以采用以下3种方法定义结构体类型变量。
1) 先声明结构体类型,再定义该类型的变量
2) 在声明类型的同时定义变量
如: struct Student{
int num;
char name[20];
char sex;
float score;
char addr[30];
}student1, student2;
这种定义方法的一般形式为
struct 结构体名
{
成员表列
}变量名表列;
3、 不指定类型名而直接定义结构体类型变量
其一般形式为
struct
{
成员表列
}变量名表列;
指定了一个无名的结构体类型,它没有名字(不出现结构体名)。显然不能再以此结构体类型去定义其它变量。这种方式用得不多。
二、结构体变量的初始化和引用
在定义结构体变量时,可以对它初始化,即赋予初始值,然后引用这个变量。如输出它的成员的值。
1、 在定义结构体变量时可以对它的成员初始化。初始化列表是用花括号括起来的一些
常量,这些常量依次赋给结构体变量中的各成员。注意:是对结构体变量初始化,而不是对结构体类型初始化。如:
struct Student b = {.name = “Zhang Fang”}; //在成员名前有成员运算符“.”
2、 可以引用结构体变量中成员的值,引用方式为
结构体变量名,成员名
如:student1,num表示student1变量中的num成员,即student1的num(学号)成员。在程序中可以对变量的成员赋值,如:
student1.num = 10010;
“.”是成员运算符,它在所有的运算符中优先级最高,因此可以把student1,num
作为一个整体来看待,相当于一个变量。上面赋值语句的作用是将整数10010赋给
student1变量中的成员num。
3、 如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低一级的成员。只能对最低级的成员进行赋值或存取以及运算。如果在结构体struct Student类型的成员中包含另一个结构体struct date类型的成员birthday,则引用成员的方式为
student1.num //结构体变量student1中的成员num
student1.birthday.month //结构体变量student1中的成员birthday中的成员month
4、 对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定
可以进行的运算)。如:
student2.score = student1.score; //赋值运算
sum = student1.score + student2.score; //加法运算
student1.age++; //自加运算
5、 同类的结构体变量可以互相赋值。如:
student1 = student2;
//假设student1和student2已定义为同类型的结构体变量
6、 可以引用结构体变量成员的地址,也可以引用结构体变量的地址。如:
scanf(“%d”, &Student1.num); //输入&Student1.num的值
printf(“%o”, &student1); //输出结构体变量&studnet1的首地址
但不能用以下语句整体读入结构体变量,如:
scanf(“%d, %s, %c, %d, %f, %s\n”, &student1);
三、使用结构体数组
一个结构体变量中可以存放一组有关联的数据(如一个学生的学号、姓名、成绩等数据)。如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。结构体数组与以前介绍过的数值型数组的不同之处在于每个数组元素都是一个结构体类型的数据,它们分别包括各个成员项
1、 定义结构体数组
1) 定义结构体数组一般形式是
① struct结构体名
{成员表列} 数组名[数组长度];
② 先声明一个结构体类型(如struct Person),然后再用此类型定义结构体数组:
结构体类型 数组名[数组长度];
如:
struct Person leader[3]; //leader是结构体数组名
2) 对结构体数组初始化的形式是在定义数组的后面加上
={初值表列};
如:
struct Person leader[3] = {“Li”, 0, “Zhang”, 0, “Sun”, 0};
四、结构体指针
所谓结构体指针就是指向结构体变量的指针,一个结构体变量的起始地址就是这个结构体变量的指针。如果把一个结构体变量的起始地址存放在一个指针变量中,那么这个指针变量就指向该结构体变量。
1、 指向结构体变量的指针
指向结构体对象的指针变量即可指向结构体变量,也可以指向结构体数组中的元素,指针变量的基类型必须与结构体变量的类型相同。如:
struct Student *pt; //pt可以指向struct Student类型的变量或数组元素
2、 指向结构体数组的指针
可以用指针变量指向结构体数组的元素
3、 用结构体变量和结构体变量的指针作函数参数
将一个结构体变量的值传递给另一个函数,有3个方法:
1) 用结构体变量的成员作参数。如:用stu[1].num或stu[2].name作函数实参,将实参值传给形参。用法和用普通变量作实参是一样的,属于“值传递”方式。应当注意实参与形参的类型保持一致。
2) 用结构体变量作实参。用结构体变量做实参时,采取的也是“值传递方式”,将结构体变量所占的内存单元的内容全部按顺序传递给形参,形参也必须是同类型的结构体变量。在函数调用期间形参也要占用内存单元。这种传递方式在空间和时间上开销较大,如果结构体的规模很大时,开销是很可观的。此外,由于采用值传递方式,如果在执行被调用函数期间改变了形参(也是结构体变量)的值,该值不能返回主调函数,这往往造成使用上的不便。因此一般少用这种方法。
3) 用指向结构体变量(或数组元素)的指针作实参,将结构体变量(或数组元素)的地址传给形参。
五、用指针处理链表
1、 什么是链表
链表是一种常见的主要的数据结构。它是动态地进行存储分配的一种结构。
链表有一个“头指针”变量,链表中每一个元素称为“结点”,每个结点都应该包括两个部分:1)用户需要用的实际数据;2)下一个结点的地址。
2、 建立简单的静态链表
下面通过一个例子来说明怎样建立和输出一个简单链表
如:建立一个简单的链表,它由3个学生数据的结点组成,要求输出各结点中的数据
解题思路:声明一个结构体类型,其成员包括num(学号),score(成绩),next(指针变量)。将第一个结点的起始地址赋给头指针head,将第2个结点的起始地址赋给第1个结点的next成员,将第3个结点的起始地址赋给第2个结点的next成员。第3个结点的next成员赋予NULL。这就形成了链表。
编写程序:
#include
struct Student{ //声明结构体类型struct Student
int num;
float score;
struct Student *next;
};
int main()
{
struct Student a, b, c, *head, *p;
//定义3个结构体变量,a,b,c作为链表的结点
a. num = 10101; a.score = 89.5;//对结点a的num和score成员赋值
b. num = 10103; b.score = 90; //对结点b的num和score成员赋值
c. num = 10107; c.score = 85; //对结点c的num和score成员赋值
head = &a; //将结点a的起始位置赋给头指针head
a. next = &b; //将结点b的位置赋给a结点的next成员
b. next = &c; //将结点c的位置赋给a结点的next成员
c. next = NULL;//c结点的next成员不存放其他结点地址
p = head; //使p也指向a结点
do
{
printf(“&ld%5.1f\n”,p->num, p->score);
//输出p指向的结点的数据
p = p->next; //使p指向下一结点
}while(p != NULL); //输出完c结点后p的值为NULL,循环终止
return 0;
}
运行结果:输出3个结点中的数据
3、 建立动态链表
所谓建立动态链表是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输出各结点数据,并建立起前后链接的关系。
六、共用体类型
1、什么是共用体类型
有时想用一段内存单元存放不同类型的变量。这种使几个不同的变量共享同一段内存的结构,称为“共用体”类型的结构。
定义共用体类型变量的一般形式为
union 共用体名
{
成员表列;
}变量表列;
2、 引用共用体变量的方式
只有先定义了共用体变量才能引用它,但应注意,不能引用共用体变量,而只能引用共用体变量中的成员。如:
a.i //引用共用体变量中的整型变量i
a.ch //引用共用体变量中的字符变量ch
a.f //引用共用体变量中的实型变量f
3、共用体类型数据的特点
在使用共用体类型数据时要注意以下一些特点:
1) 同一个内存段可以用来存放几种不同类型的成员,但在每一瞬间只能存放
其中一个成员,而不是同时存放几个。其道理是显然的,因为在每一个瞬间,存储单元只能有唯一的内容,也就是说,在共用体变量中只能存放一个值。
2) 可以对共用体变量初始化,但初始化表中只能有一个常量。
3) 共用体变量中起作用的成员是最后一次被赋值的成员,在对共用体变量中
的一个成员赋值后,原有变量存储单元中的值就取代。
4) 共用体变量的地址和它的成员的地址都是同一地址。
5) 不能对共用体变量名赋值,也不能企图引用变量名来得到一个值。
6) 以前的C规定不能把共用体变量作为函数参数,但可以使用指向共用体变
量的指针作为函数参数。C99允许用共用体变量作为函数参数。
7) 共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,
结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。
七、使用枚举类型
如果一个变量只有几种可能的值,则可以定义为枚举类型。所谓“枚举“就是指把可能的值一一列举出来,变量的值只限于列举出来的值的范围内。
声明枚举类型用enum开头。如:
enum Weekday{sun, mon, tue, wed, thu, fri, sat};
以上声明了一个枚举类型enum Weekday。然后可以用此类型来定义变量。如:
enum Weekday workday,weekend;
枚举类型 枚举变量
workday和weekend被定义为枚举变量,花括号中的sun,mon,…,sat称为枚举元素或枚举常量。它们是用户指定的名字。枚举变量和其他数值型量不同,它们的值只限于花括号中指定的值之一。
声明枚举类型的一般形式为
enum [枚举名]{枚举元素列表};
其中枚举名应遵循标识符的命名规则,上面的Weekday就是合法的枚举名。
八、用typedef声明新类型名
除了可以直接使用C提供的标准类型名(如int,char,float,double和long等)和程序编写者自己声明的结构体、共用体、枚举类型外,还可以用typedef指定新的类型名来代替已有的类型名。有以下两种情况:
1) 简单地用一个新的类型名代替原有的类型名
2) 命名一个简单的类型名代替复杂的类型表示方法
C允许程序设计者用一个简单的名字代替复杂的类型形式。如:
① 命名一个新的类型名代表结构体类型
② 命名一个新的类型名代表数组类型
③ 命名一个新的类型名代表指针类型
④ 命名一个新的类型名代表指向函数的指针类型
归纳起来,声明一个新的类型名的方法是:
a、 先按定义变量的方法写出定义体(如:int i;)。
b、 将变量名换成新类型名(如:将i换成Count)。
c、 在最前面加typedef(如:typedef int Count)。
d、 然后可以用新类型名去定义变量。
简单地来说,就是按定义变量的方式,把变量名换上新类型名,并且在最前面加“typedef”,就声明了新类型名代表原来的类型。