聚合数据类型(能够同时存储超过一个的单独数据):C提供了两种类型的聚合数据类型,数组和结构。
数组:相同类型的元素的集合,它的每个元素(元素长度相同)是通过下标引用或指针间接访问来选择的。
结构:是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。(一个结构的成员长度可能不同,所以不能使用下标来访问它们)每个结构成员都有自己的名字,它们通过名字访问。
结构体
结构声明:
struct{
int a;
char b;
float c;//三个成员:一个整数、一个字符、一个浮点数
}x; //创建了一个名为x的变量
struct{
int a;
char b;
float c;
}y[20],*z; //创建了y和z,y是一个数组,它包含了20个结构;z是一个指针,它指向这个类型的结构
注意:这两个声明被编译器当做两种截然不同的类型(z=&x;代码是非法的)
struct tag //tag是标签,结构体名称,标签字段允许位成员列表提供一个名字,允许多个声明使用同一个成员列表,并且创建同一种类型的结构
{
member-list;
}variable-list;
如;
struct SIMPLE{
int a;
char b;
float c;
}; //这个声明把标签SIMPLE和这个成员列表联系在一起
struct SIMPLE x;
struct SIMPLE y[20], *z; //这些声明使用标签来创建变量,现在,x,y和z都是同一种类型的结构变量
结构体成员的访问
结构变量的成员是通过点操作符( . )访问的。点操作符接受两个操作数。
struct Stu
{
char name[20];
int age;
};
struct Stu s;
strcpy(s.name, "xiaohua");//使用.访问name成员
s.age = 20;//使用.访问age成员
◆结构体访问指向变量的成员,有时候我们得到的不是一个结构体变量,而是指向一个结构体的指针
访问成员如下:
struct Stu
{
char name[20];
int age;
}s;
void print(struct S* ps)
{
printf("name=%s age=%d\n", (*ps).name, (*ps).age);
printf("name=%s age=%d\n", ps->name, ps->age); //推荐使用
}
结构体变量的定义和初始化,与数组相同,结构体禁止整体赋初值。
内存对齐:(拿空间来换取时间)
结构体的对齐规则:
1.第一个成员在与结构体变量偏移量为0的地址处。所以,结构体成员第一个元素默认是对齐的。
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。对齐数=编译器默认的一个对齐数与该成员大小的较小值。VS中默认的值为8 Linux中的默认值为4【每个元素的起始偏移量是自身对齐数的整数倍】
3.结构体总大小为最大对齐数(每个成员都有一个对齐数)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
结构体传参,不发生降维,尽量不要直接传结构体变量(传结构体指针)。
struct S
{
int data[1000];
int num;
}s;
void print(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
print(&s);
system("pause");
return 0;
}
如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能下降。
枚举
把可能的取值一一列举。
定义:
enum Day //星期 enum Day是枚举类型
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun //都是枚举常量,默认从0开始,依次增1
};
//也可在定义时赋初值
优点:1、增加代码的可读性和可维护性
2、与#define定义的标识符比较,枚举有类型检查,更加严谨。
3、防止了命名污染(封装)
4、便与调试
5、使用方便,一次可以定义多个常量
联合(共用体)
特征:1、共用一段内存空间;
2、联合体内所有变量地址都是一样的(都是联合体总体空间第一个字节的地址)
联合类型的声明:
特点:
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
联合大小的计算:
● 联合的大小至少是最大成员的大小。
● 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。