在C语言中提供了很多基本的数据类型,但在实际开发中,无法满足程序中各种复杂数据的要求。有时需要将不同类型的数据组合成一个有机的整体,一边引用。例如:
num | name | sex | age | score |
001 | lemon | F | 18 | 90 |
在图中列举了学生的学号、姓名、性别、年龄和成绩几个项目,这几个项目都是相互联系的。如果将这些项目分别存成相互独立的一些变量,很难反映它们之间的内在联系。应该把这些项目组合成一个组合项,在这个组合项中可以包括若干个类型相同或者不同的数据项。这种数据结构就称为结构体。
结构体是一种构造类型,由若干成员组成,每一个成员可以是一种基本的数据类型或者另一种构造类型。因为结构体是一种用户自定义的数据类型,所以在使用之前需要先定义,也就是先构造。定义一个结构体的一般格式如下:
struct 结构体名
{
成员列表;
};
其中,“结构体名”是结构体的标志;花括号内是该结构体中的各个成员,每个成员都需要进行类型说明。声明格式如下: 类型名 成员名;
根据结构体的一般格式,将前面提到的学生结构体定义如下:
注意:
1.不要忽略最后的分号。
2.struct student 是一个类型名,它和系统中提供的标准的数据类型具有相同的地位和作用,都可以用来定义变量类型,只不过结构体类型需要由用户自己定义而已。
3.结构类型体和变量是不同概念,程序员只能对变量进行相应的运算,不能对结构体类型进行运算。系统在进行编译时,仅对变量进行储存空间的分配,并不对结构体类型进行空间分配。
4.结构体类型中的成员相当于变量的作用,并且,结构体中的变量可以单独使用。
5.结构体是可以嵌套的。在使用结构体嵌套时,要先声明内部的结构体struct date再声明外部的结构体struct student.在定义结构体类型struct student时,使用结构体
6.结构体类型中的成员变量可用于程序中其他变量同名。
上文介绍了结构体类型,该类型就相当于一个模型,在这个模型中没有具体的数据,编译器也不为其分配实际的内存单元。结构体类型定义后就可以使用了,下面介绍三种定义结构体类型变量。
在前面定义了结构体类型struct student,可以用该结构体类型定义变量。
例如,定义一个结构体类型的变量stu如下:
struct student (结构体类型名) stu ;(结构体变量名)
这里定义了一个名为stu的struct student类型的变量,也就是说它拥有struct student的结构。
变量stu被定义后,系统会为其分配内存单元。对于每一个struct student类型的变量,系统都会为其分配33个字节的内存空间(4+20+1+4+4)。
说明:
如果要编写的程序规模比较大,经常会将这些结构体类型的声明存放在一格后缀名为.h的文件中,如果某个程序需要该结构体,就可以用#include命令将该头文件包括进来,从而便于程序员的修改和使用。
直接声明结构体变量,是指不声明结构体名称,直接定义结构体类型。它与第二种方法比较类似,不同的是,它不需要定义结构体名称。其一般格式如下:
typedef相当于struct 结构体名;就像人的小名一样
可以直接定义结构体变量。
(1) 不能将 结构体变量作为 一个整体进行引用,比如s1,s2都是结构体变量,但不能拿过来直接用,只能对结构体变量中的 各个成员分别引用;引用的方式为:
结构体变量名 . 成员名 [这个 . 叫做结构成员运算符,该运算符优先级 非常高 ,与()平级,所以可以把 s1.num 看作是一个整体]
例如:s1.num=1001; //将1001赋值给s1变量中的成员num
(2) 如果成员本身 又属于一个结构体类型,则要用若干个成员运算符,一级一级的找到最低一级成员,只能对最低级成员进行赋值或者存取。
s1.birthday.month=12;
s1.birthday.day=30;
s1.birthday.year=2018;
(3) 成员变量,就当成普通变量,可以像普通变量一样进行各种运算
s2.age=s2.age; //赋值
int agesum=s2.age+s2.age; //求年龄和
s1.age++; //年龄自加1,因为 . 的优先级最高,所以s1.age是个整体。
//s1++; 这样是不可以的这样写的。也不可以这样写:s1.brithday++;
(4) 因为成员变量我们也是当成普通变量的,所以它们 也是有地址的。
int *p=&s1.num;
pritntf("%d\n",*p); //结果是:1001
基本初始化是最常用的结构体初始化方法,通过使用“{}”括号来初始化结构体变量。例如:
指定成员初始化可以通过指定成员名来初始化结构体的成员变量。例如
常量表达式初始化可以在结构体定义时用常量表达式对结构体成员进行初始化。
类型定义结构体数组和定义结构体类型变量的方法类似,都有3种方法。下面有3种方法定义一个结构体类型数组emp,该数组有10个元素,每个元素都是student结构体类型。
结构体指针变量的定义格式为:struct 结构体名称 *结构体指针变量名;
此时指针变量的值就是结构体数组的首地址。
例如定义一个结构体数组student[5],使用结构体指针指向该数组
代码为:struct Student*p; p=student;
也可以直接指向结构体数组的元素例:p=&student[2];
使用结构体变量作为函数的实参时,采取的是“值传递”,这种传递方式在空间和时间上开销都比较大。
共用体又称联合体,用来将几种不同数据类型的变量存放到同一段内存单元中。共用体在同一时刻只能有一个值,它属于某一个数据成员。由于所有成员存放在同一块内存中,因此共用体的大小就等于最大成员的大小。
可以看出,共用体变量的定义方式与结构体变量的定义方式相似,不过结构体变量大小是包括数据成员大小的总和,其中每一个成员分别占有自己的内存单元。
都与结构体类似:
共用体变量的引用:
共用体变量.成员名;
注:1.每一次只能存放其中一种类型,而不是同时存放所有的类型。也就是说,在共用体中只有一个成员起作用,其他的成员都不起作用。
2.共用体变量的地址与其他成员的地址都是同一地址。
3.在程序中改变共用体的一个成员,其他成员也会随之改变。当给某个特定的成员进行赋值时,其他成员的值也会在值的变化上具有一致性。(内存原因)
共同体变量的初始化赋值
定义共同体变量时可以对变量附初始值,但只能对变量的第一个成员赋初值,不可像结构体变量那样对所有的成员赋初值。
定义了共同体以后,如果要对其赋值,则只能通过成员对其赋值,不可对其整体赋值。
由于共同体变量的各成员共享同一地址的内存单元,共同体保存的是最后一次存入的成员值。