结构体
定义:结构是一些值的集合,这些值称为结构的成员变量,结构的每个成员可以是不同类型的变量
声明:举例如下
struct Stu //定义一个结构体类型Stu { char name[20]; // 定义一个成员变量name int age; //定义一个成员变量age char sex[5]; //定义一个成员变量sex };
特殊声明(匿名结构体类型)
struct { int a; float b; double c; }x;
对于结构体可以这样理解,struct关键字说明这是一个结构体,结构体类型名限制了结构体变量的范围,就如同int 一般,有人表示了这个变量的范围。
注:对于匿名结构体,如果两个匿名结构体的成员是一样的,千万不要以为它们是一个结构体,编译器可不这样认为。
结构体的访问
通过".","->"访问
int main() { struct Stu s; struct Stu *p; s.age = 20; //点运算符的左边操作数是一个结果为结构的表达式 strcpy(p->name , "zhangsan"); //箭头的左边操作数是一个指向结构体的指针 return 0; }
结构体的自引用
在结构体中包含一个类型为该结构本身的成员。(链表的举例)
struct Node { int data; struct Node *next; //指向同类型数据的指针 };
结构体的内存对齐
对于结构体的内存对齐通常解释有以下两个原因
1.平台原因
不是所有的硬件平台都能访问
任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常
2.性能原因
数据结构(尤其是栈)应该尽可能在自然边界上对齐,因为对于没有对齐的内存,处理器需要做两次数据访问,而对于对齐的数据内存,处理器只需要做一次数据访问
结构体对齐原则:
1.第一个成员在于结构体变量偏移量为0的地址处
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处,对齐数为编译器默认的对齐数与该成员大小的较小值
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
4.如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
举个栗子:
struct S3 //16 { double d; char c; int i; }; struct S4 //32 { char c1; struct S3 s3; double d; };
对于第一个结构体而言,根据上述规则,大小为 8+1+3+4 = 16
对于第二个结构体而言,也根据上述规则,可以得到 1+7+16+8 = 32
从上面的两个例子我们可以看到都存在内存浪费的问题,那么,怎么让内存见谅不会被浪费呢?答案是,让占用空间小的成员尽量集中在一起。
结构体传参
结构体传参的时候尽量传入地址,因为函数传参的时候,参数是需要压栈的,如果所传入的结构体过大,参数压栈的系统开销比较大,会导致性能的下降
举例如下:
struct S3 { double d; char c; int i; }; void print(struct S3 *ps) { printf("%c\n", ps->c); } int main() { struct S3 s3 = { 0.0, 'a', 2 }; print(&s3); return 0; }
位段
1.位段的成员必须是int, unsigned int,signed int.
2.位段的成员名有一个冒号和一个数字
比如下面的例子:
struct A { int _a : 2; int _b : 5; int _c : 10; int _d : 30; };
位段的内存分配
1.位段的的成员可以是int ,unsigned int ,signed int 或者是char (属于整型家族)类型
2.位段的空间上是按照需要以4个字节(int)或者1个字节(char)的方式来开辟的
3.位段是涉及很多不确定的因素,位段是不跨平台的,注重可移植的程序应该避免使用位段
下面的例子又是怎么样开辟空间的
struct S { char a : 3; char b : 4; char c : 5; char d : 4; }; struct S s = { 0 }; s.a = 10; s.b = 12; s.c = 3; s.d = 4;
分析一下可得总共需要开辟三个字节的空间。
枚举
enum Sex { MALE, FEMALE, SECERET }; //可以直接在大括号外面写变量名称,但是这样创建的是全局的变量,所以不太使用
联合体
联合体的成员是共用一块内存空间的,共用的是对应字节的空间,其中一个改变影响另外一个成员
联合体大小的计算
1.联合体的大小最少是最大成员的大小
2.当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
union ip_addr { unsigned long addr; //四个字节的内容要一个一个字节的拿出来,而如果直接后面写4个char类型的,只是拿到了第一个。 struct { unsigned char a; //用无符号的,因为范围的取值 unsigned char b; unsigned char c; unsigned char d; }ip; }; int main() { union ip_addr my_ip ; my_ip.addr = 176238749; //让第一个无符号整型的值为ip地址 printf("%d.%d.%d.%d\n", my_ip.ip.a, my_ip.ip.b, my_ip.ip.c, my_ip.ip.d); return 0; }结果如下: