1.结构体类型的创建
结构体是一些值的集合,这些值称为成员变量,结构体的每个成员可以是不同类型的变量。
例如描述一个学生
struct Stu { char name[20];//名字 int age;//年龄 char sex[5];//性别 char id[20];//学号 };//分号不能丢
2.结构体的定义和初始化
struct Point { int x; int y; }p1;//声明类型的同时定义变量p1 struct Point p2;//定义结构体变量p2 //初始化:定义变量的同时赋初值 struct Point p3={x,y}; struct Stu//类型声明 { char name[15];//名字 int age;//年龄 }; struct Stu s={"zhangsan",20};//初始化 struct Node { int data; struct Point p; struct Node* next; }n1={10,{4,5},NULL};//结构体嵌套初始化 struct Node n2={20,{5,6},NULL};//结构体嵌套初始化
注意:结构体只允许整体初始化,不允许整体赋值
3.结构体内存对齐
结构体的对齐规则
(1)第一个成员在与结构体变量偏移量为0的地址处。
(2)其他成员变量对齐到某个数字(对齐数)的整数倍的地址处。对齐数=编译器默认的对齐数与该成员大小的较小值。vs默认的值为8,linux默认的值为4。
(3)结构体大小为最大对齐数(每个成员变量除了第一个成员都有一个对齐数)的整数倍。
(4)如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
#include <stdio.h> struct S1 { double d; char c; int i; }; struct S2 { char c1; struct S1 s1; double d; }; int main() { printf("S1-->%d\n",sizeof(struct S1)); printf("S2-->%d\n",sizeof(struct S2)); return 0; }
以上述代码为例,这里采用vs编译器。在结构体S1中,d,c,i的对齐数分别是8,1,4,d是第一个变量,默认是对齐的,因此偏移量为0,大小为8,变量c偏移量为8,能整除对齐数1,因此大小为1,变量d偏移量9,不能整除对齐数4,所以+3使其能够整除,因此变量i的大小7, 所以8+1+7=16,16可以整除最大对齐数8,因此结构体大小为16。S2与上述过程基本一致。
4.位段
位段的声明和结构体是类似的,有两个不同:
(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)或者一个字节(char)的方式来开辟的。
(3)位段涉及很多不确定因素,位段是不跨平台的,注重柯移植的程序应该避免使用位段。
5.枚举
枚举的定义
enum Color { RED, GREEN, BLUE };
枚举的优点
(1)增加代码的可读性和可维护性
(2)跟#define定义的标识符比较枚举有类型检查,更加严谨
(3)防止了命名污染(封装)
(4)便于调试
6.联合(共用体)
联合(共用体)的定义
联合也是一种特殊的自定义类型,这种类型页包含一系列的成员,特征是这些成员共用同一块空间(所以也叫共用体)。比如:
union Un { char c; int i; };
联合大小的计算
(1)联合的大小至少是最大成员的大小。
(2)当最大成员大小不是最大对齐数的整数倍的时候。就要对齐到最大对齐数的整数倍