1、结构体
(1)结构体的声明
结构体中的每个成员可以是不同类型的变量
例如:描述一个学生
struct Stu
{
char name[20];
int age;
char sex[5];
char id[20];
};
(2)结构体的自引用
struct Node
{
int datd;
struct Node* next;
};
(3)结构体变量的定义和初始化
声明类型的同时定义变量p1
struct Point
{
int x;
int y;
}p1;
初始化
struct Point p2={x, y};
(4)结构体内存对齐
计算机访问内存的基本单位是字节,计算机能任意读取内存中的任何一个字节,计算机因为硬件设计的原因,读取数据时必须从特定要求的位置开始读取。
结构体内存对齐的本质:用空间换取时间
结构体的对齐规则:
1>第一个成员在与结构体变量偏移为0的地址处
2>除了第一个成员之外的其他成员变量对齐到某个数字(对齐数)的整数倍的地址处,即就是该变量的起始偏移量能够整除当前变量的对齐数
3>结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
4>如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
举例:
struct S1
{
char c1;
int i;
char c2;
};
printf("%d\n", sizeof(struct S1));
分析:
(5)修改默认对齐数
#include<stdio.h>
#pragma pack(1)
struct S1
{
char c1;
int i;
char c2;
};
#pragma pack()设置对齐数
(6)结构体传参
结构体传参时,要传结构体的地址
#include<stdio.h>
#include<windows.h>
struct S
{
int data[1000];
int num;
};
struct S s = { { 1, 2, 3, 4 }, 1000 };
void print(struct S* ps)
{
printf("%d\n", ps->num);
}
int main()
{
print(&s);
system("pause");
return 0;
}
2、位段
位段的成员必须是int,unsigned int ,signed int 或 char类型
位段的成员名后边有一个冒号和一个数字
位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的
位段是不跨平台的
例如:
struct A
{
int a : 2;
int b : 5;
int c : 10;
int d : 30;
};
位段的大小是受平台影响的,位段的空间分配采用“压缩存储”方式,如果剩下的比特位数目能够容纳当前变量,大家就挤一挤;如果不能,则重新开辟
位段A的空间分配如图所示:
位段A只开辟两个整形空间,大小为8个字节
运行结果如图:
3、枚举
(1)枚举
枚举就是列举,常用来定义一大批强相关性的常量,例如:星期,月份,性别等
枚举类型的本质是int
例子:
enum Day
{
Mon;
Tues;
Wed;
Thur;
Fri;
Sat;
Sun;
};
enum Day是枚举类型,{}中的内容是枚举类型的可能取值,也叫枚举常量。这些 可能取值默认从0开始,一次递增1,在定义时也可以赋初值。
例如:
(2)枚举与#define定义常量
枚举是一种类型,在编译时会进行类型检查;
宏是基于替换原则,在这个过程中并不进行任何检查工作
宏的应用场景>>枚举
4、联合(共用体)
联合也是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特征是这些成员共用同一块空间。
例如:
联合体本身的大小并不是把所有的类型加起来的大小,常规而言,联合体的大小是由联合体内最大元素的大小觉得的,决定了之后,所有元素共享空间。
在使用union时,一次只会访问一个元素。
联合体的声明:
union Un
{
char c;
int i;
};
联合变量的定义:
union Un un;
计算联合变量的大小:
联合体也要考虑内存对齐的问题,联合体的最终大小要能整除联合体内最大对齐数