第七部分:自定义数据类型
一、结构体的概念与定义
在前面的学习中,变量大多都是互相独立的,即使是内存中的地址也是互相毫无干系的。即使是数组,也只是要求其中的元素必须是同样的类型。那么可以不可以有一种结构,可以将一些不同类型的变量放在一起,而他们又具有一定的联系呢?例如一个学生的资料,其中有学号、姓名、性别、年龄、地址。C 语言中允许用户自己建立由不同类型数据组成的组合型数据结构,叫做“结构体”。可以理解为结构体也是一种数据类型,例如下面是一个自行创建的结构体类型:
struct Student
{
int num;
char name[20];
char sex;
int age;
char add[30];
};
struct
是结构体类型的标识符,Student
是用户自定义的结构体名称,就像 int a
中的 a
是变量名称一样。这个结构体中有 5 个成员,分别是 num
、name
、sex
、age
、add
,它们各自有自己的数据类型。这个结构体在内存中占 4 + 20 + 1 + 4 + 30 = 59 字节。上面定义的结构体可以这样示意:
Student | ||||
num | name | sex | age | add |
定义结构体的一般形式为:
struct 结构体名
{
//成员表列
类型名 成员名;
};
定义结构体的时候不要忘了末尾有分号。结构体表现的是“包含”关系,如上例即表示 Student
中包含了 num
、name
、sex
、age
、add
五个元素。当然,结构体的成员可以属于另外一个结构体,例如:
struct Date
{
int month;
int day;
int year;
} ;
struct Student
{
char name[20];
int age;
char sex;
char add[30];
struct Date birthday;
} ;
这个时候,此结构体的结构如下图所示:
Student | |||||||
name | age | sex | add | birthday | |||
month | day | year |
二、结构体类型的变量
当定义好了一个结构体,可以视为定义好了一个类型。比如学生是一个类型,这个类型具有学号姓名等属性。当我们定义好了这一类型的属性后,就要说明谁属于这个类型。比如王小明和张小红都是学生,这样它们就都具有学生这一类型应有的特征。这时候王小明和张小红就是学生这个结构体类型的变量。写在程序中如下:
struct Student
{
char name[20];
int num;
char add[30];
} hong, ming;
这个时候hong和ming的结构如下图所示:
name | num | add | |
---|---|---|---|
hong | |||
ming |
声明结构体类型的变量有两种方法,其中一种是在定义结构体的时候直接声明结构体变量,一般形式如下:
struct 结构体名
{
//成员表列
类型名 成员名;
} 变量1, 变量2, ……, 变量n;
注意分号是在变量表列之后的。还有一种定义方式,就是在已经定义好结构体之后,直接使用结构体名当类型名来定义,如下:
struct Student ming;
声明结构体变量的同时也可以直接对其进行初始化,下面这个例子介绍了结构体变量初始化和引用的方法:
#include<stdio.h>
int main()
{
struct Student
{
int num;
char sex;
char name[20];
char add[30];
} a = {1405010314, 'M', ming, "Beijing"};
printf("number : %d\n", a.num);
printf("name : %s\n", a.name);
printf("sex : %c\n", a.sex);
printf("address : %s\n", a.add);
return 0;
}
程序的运行结果是:
number : 1405010314
name : ming
sex : M
address : Beijing
三、结构体数组
结构体数组的概念很好理解,即一次性声明具有相同类型的结构体变量。例如:
struct Student
{
int num;
char name[20];
} stu[3] = {001 , "ming" , 002 , "hong" , 003 , "hua"} ;
当结构体数组成员很多的时候,可以不在声明的时候进行初始化。
四、结构体与指针的结合
如果声明结构体类型的指针变量,这样的话就可以让指针在结构体数组上移动。结构体中有一个叫做 NEXT
的指针类型元素,它指向结构体数组的下一个元素首地址,这样一串结构体就被串连在一起,形成“链表”。一串结构体的最后一个变量 NEXT
成员指向 NULL
,即空指针,代表一个链表的结束。链表属于数据结构部分的内容,不在这里详细讲解,有兴趣可以查阅参考资料 1 的教材内容。
五、枚举类型 enum
当一个变量只有几种值可以选择,这种变量称为枚举类型。声明枚举类型的关键字是 enum
,变量的值域只在列出的值之中。例如:
enum Week{ Sun, Mon, Tue, Wed, Thu, Fri, Sat };
这个时候我们定义了一个枚举类型 Week
,我们就可以用这个类型来定义变量:
enum Week Sep_1st, Oct_2nd;
这个时候 Sep_1st
和 Oct_2nd
都是 Week
类型的变量了,它们的值只能是已定义的 Week
类型的值其中之一。声明枚举类型的一般形式为:
enum 枚举名 { 枚举元素列表 };
六、其他的自定义类型
除了结构体和枚举类型之外,我们还有共用体类型没有详细讲解,可以查看参考资料 1 的教材自行了解。
我们还可以使用 typedef
来指定新的类型名来代替已有类型名。例如:
typedef int Zheng;
即指定 Zheng
这个类型名来代替 int
。这个方法同样适用于重新定义结构体类型等。
七、练习题
建立一个学生通讯录,可以用户自行输入数据,然后全体输出。
定义一个结构体变量,包含年、月、日三个元素。然后设计一个函数可以计算这天在这一年中是第几天。注意闰年的问题。