结构体是一些值的结合,这些值被称为成员变量。结构体的每个成员可以是不同类型的变量,如:标量、数组、指针、甚至是其他结构体。
struct tag//结构体类型
{
member-list//结构体成员
} variable-list//变量
如描述一个学生时
struct student
{
char name[20];
double height;
int age;
} ;
struct student stu1,stu2;
struct student
{
char name[20];
double height;
int age;
}stu1,stu2 ;
struct
{
char name[20];
double height;
int age;
}stu1;
·匿名结构体如果没有对结构体进行重命名的话,基本上只能使用一次。
·结构体定义不分配地址,结构体变量会分配地址。
·结构体变量的声明必须在主函数上或者主函数中
int main()
{
struct stu s1={"zhangsan",1.85,18};
struct stu s2={"lisi",1.78,16};
……;
}
s1.name
s1.age
stuct student*p=&s1;
p->age=18;
p->name="zhangsan"
typedef struct student
{
char name[20];
int age;
} stu;//相当于struct student;
stu s1={"zhangsan",18};
stu*p=&s1;
typedef主要目的是使结构体表达更加简洁,可以理解为给结构体重命名。
struct student
{
int age;
struct student;
};
上述写法正确吗?我们从sizeof(student)角度来分析,一个结构体包含自己显然它的大小就是无穷大,这是不合理的。所以想要一个结构体进行自引用,应该让结构体包含自己的指针
struct student
{
int age;
struct student*NEXT;
} ;
结构体的创建与初始化我们已经掌握了,接下来我们来探讨一个问题:计算结构体的大小,这就联系到结构体内存对齐
对齐数=编译器默认对齐数和该成员变量大小的较小值
-VS中默认对齐数是8
-Linux和gcc中没有默认对齐数,对齐数就是成员自身的大小
由上面两张图可以发现结构体成员定义先后顺序不同,结构体的大小也不一样。这是为什么呢?接下来就用结构体内存对齐来讲解下。(VS环境)
第一幅图a填在偏移量为0的地方,i为int类型对齐数为4所以必须填在4的整数倍的位置,所以i填在4处,b为char类型对齐数为1所以只要填在1的整数倍的位置 所以接在i下面填在8出但是0~8的大小为9,该结构体中最大对齐数是i的对齐数4,9不是4的倍数所以结构体最后大小是12。
图二同理,可以自己去验证下。
不是所有的硬件平台都能访问任意地址上的任意数据的,某些平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
数据结构(尤其是栈)应该是尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内容,处理器需要作两次内存访问;而对齐的内容访问仅需要访问一次。假设处理器总是从内存中去8个字节,则地址必须是8的倍数,如果我们能保证将所有的double类型的数据都对齐成8的倍数,那么就可以用一个内存操作来读或者写值了。否则,我们可能需要执行两次访问,因为对象可能被分在两个8字节内存块中。
总的来说:结构体内存对齐就是那空间来换时间的做法。
所以如果我们在设计结构体的时候既要满足对齐又要节省空间,就要对定义成员的顺序进行一定的规划。如上面两张图的差别。
#pragma pack(4)//修改默认对齐数为4
struct s
{
……
};
#pragma pack()//取消设置的对齐数,还原为默认
int main()
{
}
位段的目的:节省空间
struct A
{
int _a:2;
int _b:5;这里的数字是指比特位(bit)
int _c:10;
int _d:30;
};
A就是位段的类型。位段A所占大小为8字节(原理:2+5+10+30=47bit ,一个int(整型)四个字节,32个比特位,显然一个整型不足以存放位段A,所以需要两个整型,也就是8个字节)
VS环境下的位段开辟:1.从右向左使用。
2.如果剩余的空间不够下一个成员使用就浪费。
struct S
{
char a:3;
char b:3;
char c:4;
char d:5;
};
struct S s={0};
s.a=10;
s.b=12;
s.c=6;
s.d=8;
可以看到内存中确实是我们所推理的那样,存放22 06 08
联合体也和结构体一样由一个或者多个元素组成,联合体的特点是所有成员共用一块内存空间。所以联合体也叫共用体
union Un
{
char a;
int i;
};
int main()
{
union Un un={0};//联合变量定义
printf(“%d”,sizeof(un));//4
}
为什么上述声明的联合体大小是4个字节,上面讲到联合体成员是共用一块内存空间的,这样就使联合体的大小,至少是最大成员的大小。
在描述不同的商品比如:图书,杯子,衬衫时。每一种商品都有价格、库存量等但是他们又都有单独特有的属性页数、设计、尺寸。这个时候如果用结构体来描述就会十分复杂,而用联合体就可以节省空间。
最后来利用联合体特有的特性来实现上一章的大小端判断
int judge()
{
union un
{
int i;
char a;//a占一个字节在联合体中与i的第一个字节共用一块内存空间
}
un.i=1;
return un.a;
}
int main()
{
if(judge())
printf("小端”);
else
printf("大端");
}