结构体
结构体类型的创建
首先要知道结构体是什么?
- 结构体是一些值的集合;
- 这些值可以是不同的类型。
这样才可以创建一个结构体。
举个例子
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];
};//分号一定要有
特殊的结构体的创建
struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[10],*p;
上面两种结构体创建声明时,省略了标签tag,也就是struct后面的东西。
那么可以直接用p=&x吗?
警告:编译器会把他们当成两个不同的类型所以是非法的。
结构体的自引用
struct Node
{
int data;
struct Node* next;//必须是指针
};
typedef struct
{
int data;
Node* next;
}Node;//这样写是完全不行的
//正确的应该是
typedef struct Node
{
int data;
struct Node* next;
}Node;
结构体的初始化
struct point
{
int x;
int y;
}p = {1,2};//声明类型的同时定义结构体的变量以及初始化
struct point p1 = { 1,2 };//定义结构体的变量以及初始化
struct Node
{
int data;
struct point f;
struct Node* next;
}n1={5,{1,2},NULL};
struct Node n2 = { 5,{1,2},NULL };//结构体嵌套初始化
结构体内存对齐
结构体内存对齐的大小求值主要是通过下面四个步骤计算:
- 第一个成员在结构体偏移位为0的地址上
- 其它成员变量要对齐到某个数字(对齐数)的整数倍上
对齐数:编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8,Linux中的默认值为4- 结构体最终数为最大对齐数的整数倍数
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
举个例子:
struct S1
{
char a; // 1
double b; // 8
char c;// 1
};
//大小是多少?
//结构嵌套内存对齐
struct S2
{
char a; // 1
struct S1 p;//24
double b; // 8
};
int main()
{
printf("%d\n", sizeof(struct S1));//24
printf("%d\n", sizeof(struct S2));//40
system("pause");
return 0;
}
根据上面的步骤来不难计算出来,24和40。
我们有没有思考过为什么存在内存对齐?
//1.平台原因:不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
//2.性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问只需要一次。>
//3.总的来说:结构体内存对齐就是用空间换时间。
设计结构体的时候我们要节省空间又要节省时间,那什么样才是最佳的结构体设计呢?
struct S
{
char a;
double b;
char c;
};
struct S1
{
char a;
char c;
double b;
};
S1明显比S更节省空间。
如果对齐数不合适的时候,我们可以怎么办呢?
修改对齐数
#pragma pack(4)
struct S
{
char a;
double b;
char c;
};
#pragma pack()//取消默认对齐数
int main()
{
printf("%d\n", sizeof(struct S));//16
system("pause");
return 0;
}
结构体位段的实现
位段的声明
位段的声明和结构体是类似的,只有两点不同。
- 位段的成员必须是int,unsigned int,signed int或者char类型。
- 位段的成员名后边有一个冒号和一个数字。
举个例子
struct A
{
int a : 2;
int b : 5;
int c : 10;
int d : 30;
};
int main()
{
printf("%d\n", sizeof(struct A));//8
system("pause");
return 0;
}
和结构体比较,位段可以很好的节省空间,但是存在跨平台问题。
位段计算大小时不考虑对齐问题。
枚举
定义
enum DAY//星期
{
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum SEX//性别
{
MALE,
FEMALE,
SECRET
};
enum COLOR//颜色
{
RED,
BLUE,
BALCK,
WRITE
};
上面的enum SEX, enum COLOR ,enum DAY,都是枚举类型,{ }里面的是枚举常量。
枚举的默认初值是0,然后依次递增加一,当然也是可以赋初值。
enum COLOR//颜色
{
RED=1,
BLUE,//2
BALCK,//3
WRITE=8
};
特点
1.增加代码的可读性和可维护性
2.便于调试
3.一次可定义多个变量
4.防止了命名污染(封装)
5.和#define比较有类型检查,更加严谨
使用
联合
定义
联合是一种特殊的自定义结构体,这个结构体包括了多个成员,而这些成员共用一个空间,因此联合也叫作共用体。
特点
联合的成员共用一块内存空间,这样一个联合的内存空间至少是最大成员的大小。
计算
- 联合的大小最小也是最大成员的大小
- 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
举例