一.结构体嵌套结构体
1.含义
一个结构体中成员可以是另外一个结构体
2.语法结构
struct 结构体名
{
struct 结构体名 成员名;
};
3.代码示例:
这里以需要储存老师和学生的信息为例子,老师的部分信息和学生的部分信息需要存储的是一样的
#include <stdio.h>
#include <string.h>
struct person
{
char name[16];
int age;
};
struct tea
{
int salary;
struct person teaper;
};
struct stu
{
int score;
struct person stuper;
};
int main(int argc, const char *argv[])
{
struct tea tea1;
struct tea *p=&tea1;
tea1.salary=5000;
strcpy(tea1.teaper.name,"zhangsan");
tea1.teaper.age=35;
printf("salary=%d name=%s age=%d\n",p->salary,p->teaper.name,p->teaper.age);
struct stu stu1;
struct stu *t=&stu1;
stu1.score=90;
strcpy(stu1.stuper.name,"lisi");
stu1.stuper.age=20;
printf("score=%d name=%s age=%d\n",t->score,t->stuper.name,t->stuper.age);
return 0;
}
分析:
⭕在储存学生和老师信息的时候,两者的部分信息是一致的,年龄和名字都需要储存,所以我们可以定义一个共同的结构体来储存年龄和名字,然后再在两者分别的结构体中引用这个相同信息的结构;
⭕在引用结构体中的结构体成员时只需要用两个“ ..”就可以实现;
⭕需要注意的是在使用结构体指针时,指针不能连用-> ->来访问嵌套结构体成员;因为只有通过指针去访问的时候才是用"->",当用指针p访问teaper时用->连接两者,而之后此时teaper是一个变量,不是指针,所以就和普通的结构体一样用“.”又来访问它自己内部的成员;
二.结构体大小
1.字节对齐
含义:字节对齐主要是针对结构体而言的,通常编译器会自动对其成员变量进行对齐,以提高数据存取的效率;
作用:
⭕平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
⭕性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
通俗解释就是:
结构体中的数据的类型都是参差不齐的,如果要读取正确读取数据,为保证数据的完整性,就要访问两次,一次确定要数据的大小,第二次才是读取,所以就比较浪费时间,因此就有了用字节对齐来提高效率;字节对齐后,系统对结构体中的数据内存空间每次只读固定大小空间块,且不会破坏数据的完整性,相当于把数据空间进行整合,保证在每次读固定大小空间的时候,整块结构体的空间刚好都会是固定空间大小的整数倍读完,即以固定空间均分了结构体,且保证了数据的存储完整;
2.结构体大小的计算方法
自身对齐:结构体成员自身占的字节数
默认对齐:由系统或者编译器决定的字节数
有效对齐:在自身对齐和默认对齐中小的那一个就是最后对齐的字节数
地址必须能够整除有效对齐的字节数,且地址是最小地址
最后整块结构体空间必须是数据类型中自身对齐字节数最大的整数倍;
这个部分有点抽象,下面找些例子
3.结构体大小计算
分析:
如图所示 该环境是32位环境,即4个字节,用自身所占的字节数与4相比,谁小就决定最后该变有效字节数长度。a变量有效对齐字节是1个字节,然后最小能够整除1字节的地址是0(假如从开始开辟的空间),然后b变量有效对齐是4个字节,然后最小能够整除4字节的地址是4,所以a到b之间隔了4个字节地址,然后b自己占四个字节且cd变量有效对齐都是1个字节,然后最小能够整除1字节的地址是就是8和9了,最后为了让整体的空间是默认字节的整数倍,所以又添了两个空间进来
三.位域
1.位域的定义
计算机的内存是以字节为单位,为变量开辟分配内存空间。但是实际上有些变量的大小并没有用到实际分配的空间大小,有时候只需要几个二进制位就够了。比如说储存男女性别是用0和1就足够,一个二进制位就能储存,用一个char(一个字节)来存储很浪费,因此,c语言中又提出了一种数据结构,称为“位域”
所谓的“位域”是把一个字节中的二进制位分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
2.位域的一般形式
位域的一般形式:
struct 位域结构体名
{
位域列表;
};
其中位域列表的形式为: 类型说明符 位域名:位域长度
3.代码举例:
这样就用一个字节储存了三个变量;