一、结构体详解
1.结构体概述
- 结构体作用
结构体是一种自定义数据类型,可以解决数组类型单一的缺陷,即定义的结构体类型可以包含多种数据类型; - 结构体的存储
结构体在内存中是一块连续存储的空间,类似于多维数组,因此有下标和指针两种访问方式:
struct student{
char *name;
int num;
double score;
}s1; //定义变量
int main(void)
{
struct student *s2 = &s1; //定义变量
s1.name = "s1";
s1.num = 1;
s2->score = 3.14; //赋值
printf("s1.name = %s\n", s1.name); //下标访问
printf("s1.num = %d\n", *((int *)((int)&s1 + sizeof(char *)))); //指针访问
printf("s1.score = %f\n", s2->score); //指针访问
}
- 结构体变量名
结构体变量名代表的是整个结构体,因此无论是值还是地址,都代表着整个结构体;
struct str{ //定义结构体类型
char a;
char c;
};
int main()
{
struct str s1 = { //定义结构体变量
s1.a = 'a',
s1.c = 'a'
};
printf("&s1 = %p\n", &s1); //输出 &s1 = 0136F890 结构体整体首地址,子数值上等于第一个元素的地址
printf("s1 = %x\n", s1); //输出 s1 = 6161 即两个元素s1.a和s1.c的值
printf("sizeof(s1) = %d\n", sizeof(s1)); //输出 sizeof(s1) = 2 即整个结构体的大小
printf("&s1.a = %p\n", &s1.a); //输出 &s1.a = 0136F890 即结构体首元素的地址。
}
2.结构体对齐访问
#pragma pack()#pragma pack(n)#pragma pack(n)#pragma pack()
#pragma pack(1) //以1字节对齐
struct stu {
char c;
int num;
};
#pragma pack()
sizeof(stu) == 5; //该结构体占用5字节而非8字节
__attribute__((packed))__attribute__((aligned(n)))__attribute__((packed))__attribute__((aligned(n)))__attribute__((aligned(n)))__attribute__((packed))
struct stu {
char c;
int num;
}__attribute__((aligned(4)); //stu整体4字节对齐
sizeof(stu) == 8;
struct stu{
char c;
int num;
}__attribute__((packed)); //stu实际占用空间大小
sizeof(stu) == 5;
二、共用体详解
共用体概述
- 共用体类型、变量的定义与结构体相同,使用方法与结构体类似;
- 共用体内部所有成员共用一个内存空间,因此对一个成员赋值即对所有成员赋值;
- 各成员之间的区别只是数据类型不一样即解析的方式不一样;
- 共用体的大小等于成员中占最大内存的数据类型的大小,且由于共用一个内存空间,因此不涉及字节对齐;
//定义共用体
union stu{
char a;
int b;
float c;
}s1; //定义共用体变量
int main(void)
{
//定义共用体变量
union stu s1;
s1.b = 97;
//访问共用体
printf("s1.a = %c\n", s1.a); //输出 s1.a = a
printf("s1.b = %d\n", s1.b); //输出 s1.b = 97
printf("s1.c = %f\n", s1.c); //输出 s1.c = 0.000000 即三个元素实际为同一个值
printf("sizeof(s1) = %d\n", sizeof(s1)); //输出 sizeof(s1) = 8 即最大的元素double的大小
};
- 共用体本质上也可以通过指针和强制类型转换来代替
//通过强制类型转换,从s1.a得到s1.b
char *pc = &a;
printf("s1.b = %d\n", *((int *)pc));
三、枚举详解
1.枚举概述
- 枚举的作用
枚举通过声明符号来表示整型常量,来提高代码的可读性和直观,通常用在有些变量的取值被限定在一个有限的范围内,如一周从周一到周日,每月1号到31号等; - 定义
枚举的语法与结构体类似
enum color{ //定义枚举类型
red,
green,
blue =4,
yellow,
}c1; //定义枚举变量
int func1()
{
enum color c2; //定义枚举变量
c1 = red; //使用枚举
}
int str[yellow] = {0, 1, 2, 3}blue = -4yellow = -5
2.枚举与宏定义区别
- 相同点
枚举与宏定义都可以通过字符来代替某个常量,是代码更直观,二者之间大部分情况下可以替换通用。 - 不同点
枚举通常用在有顺序或某些常量的有限集合中,而宏定义更多用在独立的,相互之间无关联的定义之中。