目录
一.结构体
结构体是一些值的变量,这些值称为成员变量,结构的每个成员可以是不同类型的变量。
1.1 结构体的声明
声明一个学生类型,是通过学生类型来创建学生变量(对象),属性-姓名-年龄-性别-学号。
示例:
struct Stu
{
char name[20]; //名字;
int age;// 年龄;
char sex[5]; //性别;
char id[20]; //学号;
} s4,s5,s6;//分号不能丢,s4,s5,s6都是全局的结构体变量;
struct Stu s3;// 全局变量;
int main()
{
//创建结构体变量;
struct Stu s1;
struct Stu s2;
}
匿名结构体:
struct
{
int a;
char c;
}sa; //该方式为匿名结构体,只能用一次;
struct
{
int a;
char c;
}* psa;
int main()
{
psa=&sa; //是不行的,因为上面两种匿名结构体,系统当成了不同的两种类型;
}
1.2 结构体的自引用
顾名思义,即结构体的成员变量中有结构体。
示例:
struct Node
{
int data;
struct Node* next; //链表中,节点中,一个存放数值,一个存放下一个节点的地址;
}
1.3 结构体变量的定义与初始化
struct Point
{
int x;
int y;
}p1; //声明结构体变量的同时定义变量p1;
struct Point p2; //定义结构体变量p2;
初始化:
struct s
{
char c;
int a;
double d;
char arr[20];
};
int main()
{
struct s s1={'c',100,3.14,"hello bit"}; //结构体的初始化;
printf("%c %d %lf %s",s1.c,s1.a,s1.d,s1.arr); //打印结构体成员;
}
嵌套结构体的初始化:
struct T
{
double weight;
short age;
};
struct S
{
char c;
struct T st; //嵌套结构体的初始化;
int a;
double d;
char arr[20];
};
int main()
{
struct S s{'c',{55.6,30},100,3.14,"hello bit"};
printf("%lf\n",s.st.weight);
}
1.4 结构体的内存对齐
先看下面这个示例:
struct S1
{
char c1;
int a;
char c2;
};
struct S2
{
char c1;
char c2;
int a;
};
int main()
{
struct S1 s1={0};
printf("%d\n",sizeof(s1));
struct S2 s2={0};
printf("%d\n",sizeof(s2)); //结果为12 和 8
return 0;
}
我们可以发现结构体S1的大小为12,结构体S2的大小为8,并不是简单的将各个成员变量的大小进行相加,这主要是由于结构体存在内存对齐,其计算规则如下:
计算规则:第一个成员在与结构体变量偏移量为0的地址处,其他成员变量要对齐到某个数字(对齐数)的整数倍的地址;
对齐数=编译器默认的一个对齐数 与 该成员 大小的较小值;(VS中默认的值为8)
结构体的总大小为最大对齐数的整数倍。
解释:像上面的结构体S1,其第一个类型char类型为一个字节,此时大小为1,然后第二个数据类型为int,int的大小为4,与默认对齐数进行比较,4<8,故此时对齐数为4,故下一个数据开始存放的地方要是4的倍数,即第二个数据要从4的地方开始存储,然后int类型占4个字节,此时总大小为8; 随后,第三个为char类型,此时8是char的整数倍,故此时总大小就是9,三个数据的对齐数分别是1,4,1,其中的最大值为4,而最后的总大小要是最大对齐数的整数倍,故此时9应该再找3个空间,使得结构体的大小变为12.
同理,看结构体S2,其内存计算过程一样,第一个占据1个字节,第二个还是char类型此时占据的还是1个字节,第三个是int类型,故第三个要从4的倍数即4开始进行存储4个字节到8,然后8是4的整数倍,故最终大小就是8.
以下也提供两个示例供大家进行练习:
练习1:
struct s3
{
double d;
char c;
int i;
};
printf("%d\n",sizeof(struct s3));
练习2:
struct s4
{
char c1;
struct s3 s3;
double d;
};
printf("%d\n",sizeof(struct s4));
1.5 修改结构体的默认对齐数
可以使用 #pragma pack()这个预处理命令来修改结构体的默认对齐数
示例:
#pragma pack(4) //设置默认对齐数为4;
struct s
{
char c1; //
//7
double d;// 8
};
#pragma pack() //取消设置的默认对齐数,为了性能故不会设置成1;
1.6 结构体传参
在使用结构体时,常用的传参方式有传值与传址两种方式,以下做示例,其中最好使用传址的方式
示例:
struct S
{
int a;
char c;
double d;
};
void Init(struct S* ps)
{
ps->a=100;
ps->c='w';
ps->d=3.14;
}
void Print1(struct S tmp)
{
printf("%d %c %lf\n",tmp.a,tmp.c,tmp.d);
}
void Print2(struct S* ps)
{
printf("%d %c %lf\n",ps->a,ps->c,ps->d);
}
int main()
{
struct S s={0};
Init(&s);
Print1(s);
Print2(&s); //尽量使用这种传址的方式,原因:Print1需要压栈的,如果传过去的结构体大小过大,会导致性能的下降。
}
二. 位段
结构体讲完后,就得讲讲结构体实现位段的能力。
2.1 什么是位段
位段的声明与结构体类似,但是有两个不同
1.位段的成员必须是int、unsigned int或者 signed int;
2.位段的成员名后面有一个冒号和一个数字;
比如:
//位段——其中的位为二进制位;
struct A
{
int a:2; //a只需要2个bit位,对应2个二进制位;
int b:5; //b只需要5个bit位, 对应5个二进制位;
int c:10;
int d:30;
}; //A就是一个位段类型; //总共需要47个bit位,换算可以得到4个字节(一个字节8个bit位)
int main()
{
struct A a;
printf("%d\n",sizeof(a)); //结果为8,单位为字节;
int 4个字节,32个bit位,当放下2,5,10后只剩下15个bit位了,放不下30,此时舍弃掉剩下的15,重新来一块32的放30,故最终是两个4字节,即8字节
2.2 位段的内存分配
1.位段的成员可以是int, unsigined int, signed int 或者是char类型;
2.位段的空间上是按照需要4个字节或者1字节的方式来开辟的;
3.位段涉及很多不确定因素,不可以跨平台,注意可移植程序避免使用位段。
位段可以很好的节省空间,但是有跨平台的问题存在。
三. 枚举
枚举顾名思义就是——列举,把可能的取值一一列举。
3.1 枚举类型的定义
//枚举类型
enum Sex //性别
{
//枚举的可能取值,也叫枚举常量
MALE,
FEMALE,
SECRET
};
3.2 枚举类型的值
enum Sex
{
MALE,
FEMALE,
SECRET
};
enum Color
{
RED=2,
YELLOW=4,
BLUE=8
};
int main()
{
enum Sex s=MALE;
s=FEMALE;
enum Color c=BLUE;
printf("%d %d %d",MALE,FEMALE,SECRET); //打印结果为0 1 2,第一个默认为0,后面的+1;
printf("%d %d %d",RED,YELLOW,BLUE); //打印结果为2,4,8;
return 0;
}
如果枚举类型有进行初始化,则按照初始化的值进行打印,若没有,则第一个默认为0,后面的加一,若上面的blue不进行初始化,则此时Blue的值将变为5,即yellow的值进行加一。
四. 联合体-共用体
4.1 联合体的定义
联合也是一种特殊的自定义类型,这种类型的变量包含一系列的成员,特征是这些成员共用一块空间。
比如:
union Un
{
char c;
int i;
};
int main()
{
union Un u;
printf("%d\n",sizeof(u)); //大小为4,联合变量的大小是最大成员的大小;
printf("%p\n",&(u.c));
printf("%p\n",&(u.i));
printf("%p\n",&u); //三个得到的地址完全相同;
return 0;
}
4.2 联合体的大小计算
1.联合的大小至少是最大成员的大小;
2.当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
示例:
union Un
{
int a;//4 ,默认对齐数为8,4比较小,所以为4
char arr[5];//5,char 为1,1比8小,为1;
//最大对齐数为4
};
int main()
{
union Un u;
printf("%d\n",sizeof(u)); //结果为8
return 0;
}