目录
定义和使用结构体变量
C语言允许用户根据需要自己建立一些数据类型,并用它来定义变量。
自己建立结构体类型
前面所见到的程序中,所用的变量大多数是互相独立的、无内在联系的;有些数据是有内在联系的,成组出现的。如性别(sex)、年龄(age)、成绩(score)、地址(addr)是属于学号为10010和名为LiFang的学生的,定义一个名为Student_1的变量,在这个变量中包括以上这些项,这样使用起来就方便多了。
C语言运行用户自己建立由不同类型数据组成的组合型的数据结构,它成为结构体(structre),在其他一些高级语言中称为“记录”(record)。
如:在程序中要用到以上所说的数据结构,自己建立一个结构体类型:
例如:
struct Student
{int num; //学号为整型
char name[20]; //姓名为字符串
char sex; //性别为字符型
int age; //年龄为整型
float score; //成绩为实型
char addr[30]; //地址为字符串,注意最后有一个分号
}
上面由程序设计者指定了一个结构体类型 struct Student(srtuct是声明结构体类型时必须使用的关键字,不能省略),struct Student就是一个在本程序中可以使用的合法类型名,它向编译系统声明:这是一个“结构体类型”,它包括num、name、sex等不同类型的成员。它和系统提供的标准类型(如int、char、float等)具有相似的作用,都可以用来定义变量,只不过int等类型是系统已声明的,而结构体类型是由用户根据需要在程序中指定的。
声明一个结构体类型的一般形式为:
srtuct 结构体名
{成员列表};
注意:
结构体类型的名字是由一个关键字struct和结构体名组合而成的(例如 struct Student)。结构体名是由用户指定的,又称为“结构体标记”(structure tag),以区别于其他结构体类型。上面的结构体声明中Student就是结构体名(结构体标记)。
花括号内是该结构体所包含的子项,称为结构体的成员(member),对各成员都应进行类型声明,即:
类型名 成员名;
“成员表列”(member lits)也称为“域表”(field list),每一个成员是结构体中的一个域,成员名命名规则与变量名相同。
说明:
- 结构体类型并非只有一种,而是可以设计出许多种结构体类型,各自包含不同的成员。
- 成员可以属于另一个结构体类型。如:
struct Data //声明一个结构体类型struct Data {int month; //月 int day; //日 int year; //年 }; struct Student //声明一个结构体类型struct Student {int num; char name[20]; char sex; int age; struct Data birthday; //成员birthday属于struct Data类型 char addr[30]; };
先声明一个struct Data类型,它代表“日期”,包括3个成员:month(月)、day(日)、year(年)。然后在声明struct Student类型时,将成员librthday指定为struct Data类型。struct Student的结构如下列表所示。已声明的类型struct Data与其他类型(如int、char)一样可以用来声明成员的类型。
num name sex age birthday.month birthday.day birthdat.year addr
定义结构体类型变量
前面只是建立了一个结构体类型,它相当于一个模型,并没有定义变量,其中并无具体数据,系统对之也不分配存储单元。相当于设计好了图纸,但未建成具体的房屋。定义结构体类型的变量,并在其中其中存放具体的数据。可以采用以下3种方法定义结构体类型变量。
- 先声明结构体类型,再定义该类型的变量:
struct Student student1,student2; //结构体类型名 结构体变量名
上面定义了student1和student2为student Student类型的变量,这样student1和student2就具有struce Student类型的结构,在定义了结构体变量之后,系统会为之分配存储单元,这种方式是声明类型和定义变量分离,在声明类型后可以随时定义变量,比较灵活。
-
在声明类型的同时定义变量:例如
struct Student //声明一个结构体类型struct Student {int num; char name[20]; char sex; int age; struct Data birthday; //成员birthday属于struct Data类型 char addr[30]; } student1,student2;
它的作用与第一种方法相同,在定义时struct Student类型的同时定义两个struct Student类型的变量struct student1和struct student2。这种定义方法的一般形式为:
struct 结构体名
{
成员列表
}变量名列表;
//声明类型和定义变量放在一起进行,能直接看到结构体的结构,比较直观,在写小程序时用此方式比较方便,但在写大程序时,往往要求对类型的声明和对变量的定义分别放在不同的地方,以使程序结构清晰,便于维护,所以这种方式一般不多用。
3.不指定类型名而直接定义结构体类型变量:其一般形式为
struct
{
成员表列
}变量名表列;
//指定了一个无名的结构体类型,它没有名字(不出现结构体名)。显然不能再以此结构体类型去定义其他变量。这种方式用的不多。
说明:
1.只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型名是不分配空间的,只对变量分配空间。
2.结构体类型中的成员可以与程序中的变量名相同,但二者不代表同一对象。例如,程序中可以另定义一个变量num,它与struct Student中的num是两回事,互不干扰。
3.对结构体变量中的成员(即“域”),可以单独使用,它的作用与地位相当于普通变量。
结构体变量的初始化和引用
在定义结构体变量时,可以对它初始化,即赋予初值。然后可以引用这个变量,例如:输出它的成员的值
#include<stdio.h>
int main()
{struct Student //声明结构体类型struct Student
{long int num; //以下4行为结构体的成员
char name[20];
char sex;
char addr[20];
} a={10101,"Li Lin",'M',"123 Beijing Road"}; //定义结构体变量a并初始化
printf("NO.:%ld\nname:%s\nsex:%c\naddress:%s\n",a.num,a.name,a.sex,a.addr);
return 0;
}
//声明了一个结构体名为Student的结构体类型,有4个成员,在声明类型的同时定义了结构体变量a,这个变量具有struct Student类型所规定的结构,在定义变量的同时,进行初始化。
//在变量名a后面的花括号中提供了各成员的值,按顺序分别赋给a变量中的成员数组,最后用printf函数输出变量中各成员的值。
- 在定义结构体变量时可以对它的成员初始化。初始化列表是用花括号括起来的一些常量,这些常量依次赋给结构体变量中的各成员。注意:是对结构体变量初始化,而不是对结构体类型初始化。C99标准允许对某一成员初始化,如
struct Student b={.name="Zhang Fang"}; //在成员名前有成员运算符
“.name”隐含代表结构体变量b中的成员b.name。其他未被指定初始化的数值型成员被系统初始化为0,字符型成员被系统初始化为‘\0’,指针型成员被系统初始化为NULL。
-
可以引用结构体变量中成员的值,引用方式为
结构体变量名.成员名 例如: a.name
在程序中可以对变量的成员赋值,例如
student.num=10010;
“.”是成员运算符,它在所有的运算符中优先级最高,因此可以把student1.num作为一个整体来看待,相当于一个变量。不能企图通过输出结构体变量名来达到输出结构体变量所有成员的值,只能对结构体变量中的各成员分别进行输入和输出。
-
如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低一级的成员。只能对最低级的成员进行赋值或存取以及运算。如果在结构体struct Student类型的成员中包含另一个结构体struct data类型的成员birthday,则引用成员的方式为
student1.num //结构体变量student1中的成员num student1.birthday.month //结构体变量student1中成员变量birthday中的成员month
不能用student1.birthday来访问student1变量中的成员birthday,因为birthday本身是一个结构体成员。
-
对结构体变量的成员可以像普通变量一样进行各种运算(根据其基类型决定可以进行的运算),例如
student2.score=student1.score; //赋值运算 sum=student1.score+student2.score; //加法运算 student1.age++; //自加运算
由于“.”运算符的优先级最高,因此student1.age++是对(student1.age)进行自加运算,而不是先对age进行自加运算。
-
同类的结构体变量可以互相赋值,如
student1=student2; //假设student1和student2已定义为同类型的结构体变量
-
可以引用结构体变量成员的地址,也可以引用结构体变量的地址,例如
scanf("%d",&student1.num); //输入student1.num的值 printf("%o",&student1); //输出结构体变量student1的起始地址 但不能用以下语句整体读入结构体变量,如: scanf("%d,%s,%c,%d,%f,%s",&student1);
结构体变量的地址主要用作函数参数,传递结构体变量的地址。
例如:输入两个学生的学号、姓名、成绩,输出成绩较高的学生的学号、姓名、成绩:
#include<stdio.h>
int main()
{
struct Student
{
int num;
char name[20];
float score;
}student1,student2;
scanf("%d %s %f",&student1.num,&student1.name,&student1.score); //输入学生1的数据
scanf("%d %s %f",&student2.num,&student2.name,&student2.score); //输入学生2的数据
printf("the higther score is:\n");
if(student1.score>student2.score)
printf("%d %s %6.2f\n",student1.num,student1.name,student1.score);
else if(student1.score<student2.score)
printf("%d %s %6.2f\n",student2.num,student2.name,student2.score);
else
{
printf("%d %s %6.2f\n",student1.num,student1.name,student1.score);
printf("%d %s %6.2f\n",student2.num,student2.name,student2.score);
}
return 0;
}
- student1和student2是struct Student类型的变量。在3个成员中分别存放学号、姓名、成绩。
- 用scanf函数输入数据结构变量时,必须分别输入它们的成员的值,不能在scanf函数中使用结构体变量名一揽子输入全部成员的值。在student.name前面没有&,因为name是数组名,本身就代表地址,故不能画蛇添足地再加一个&。
- 根据student1和student2的比较结果,输出不同学生的信息。
使用结构体数组
一个结构体变量中可以存放一组有关联的数据(如一个学生的学号、姓名、成绩等数据),如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。结构体数组与以前介绍过的数值型数组的不同之处在于每个数组元素都是结构体类型的数据,他们都分别包括各个成员项。
定义结构体数组
例如:有3个候选人,每个选民只能投票选一人,要求编一个统计选票的程序,先后输出被选人的名字,最后输出各人得票结果:
#include<string.h>
#include<stdio.h>
struct Persion //声明结构体类型
{char name[20]; //候选人姓名
int count; //候选人得票数
}leader[3]={"Li",0,"Zhang",0,"Sun",0}; //定义结构体数组并初始化
//定义一个全局的结构体数组leader,它有3个元素,每一个元素包含两个成员name(姓名)和count(票数),在定义数组