我们生活中有许多数据我们可以用整型,浮点型来描述,但是如果有一天我们要描述一本书,描述它的售价,书名,页数等信息我们是无法用整型去描述的,这个时候c语言提供了结构体,结构是一些值的集合,这些值称为成员变量,结构的每个成员可以是不同的变量,所以如果我们需要描述一本书,我们就可以把它的售价,书名,页数作为一个集合定义一本书
一结构体的声明
struct stu
{
char name[20];名字
int a;年龄
};
1如果要将类型重命名,有两种方法,
(1)
typedef struct Stu
{
char name[20];名字
int a;年龄
}stu;
将struct stu重命名为stu
(2)
struct Stu
{
char name[20];名字
int a;年龄
};
typedef struct Stu stu
2 特殊的声明(这种声明的结构体又称为匿名结构体)
struct 省略了标签名
{
int a;
char b;
float c;
}x; 正是因为未写标签名,导致定义变量只能在声明结构体的时候定义,不然写两个这样的
结构体,然后在程序任意处定义变量,编译器怎么知道这个变量是哪个类型
struct
{
int a;
char b;
float c;
}*p;
如果此时我们又定义一个匿名结构体,而且和第一个结构体的成员变量类型一样
p=&x;
你觉得指针变量p的类型和x的类型是一样的吗?
虽然两个结构体成员变量类型一样,但是编译器仍认为两个结构体是不同的类型,c语言对于上述类型不匹配未有警告,但是在c++该代码会报错。
3 结构体的自引用
//代码1
struct Node
{
int data;
struct Node next;
};
如果这种类型可以,那sizeof(structNode)的值是无限大的,就像是一个无限嵌套的递归
//代码2
struct Node
{
int data;
struct Node*next;//指针大小是已经知道的,所以我们这个结构体大小是可知的
//具体用法貌似和数据结构有点相关,目前还未涉及,所以我对这个自引用的理解不深
};
4 结构体变量的定义和初始化
结构体终究是一种类型,要想存储信息只有用这种类型定义一个变量,才会在内存开辟空间,之后就是初始化的问题了,我们只要把结构体成员变量都初始化完就等价于把结构体初始化了。
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};//结构体嵌套初始化
structNoden2={20,{5,6},NULL};//结构体嵌套初始化
5 结构体内存对齐(计算结构体的大小)
struct S1
{
char c1;
int i;
char c2;
};
printf("%d", sizeof(struct S1));
要计算上面那个结构体的大小时,我们可能会认为结构体大小就是结构体成员大小之和,那结果可能是6字节,但当我们运行起来后可以发现,结果为十二,这说明计算结构体大小的规则并非如此。
所有结果都是规则导致的。
结构体对齐规则:
1.第一个成员在与结构体变量偏移量为0的地址处。
2.其他成员变量要对齐到偏移量是自己对齐数的整数倍的地址处。
(对齐数=编译器默认的一个对齐数与该成员大小的较小值)。
VS中默认的值为8
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
所以分析上述结构体大小,实际内存占用是如下图的
根据规则1第一个成员在偏移量为零处开始占用,所以不管第一个结构体成员是什么类型变量,都从0处开始占用内存,而其它的成员变量使用内存的位置则看规则2,int类型的对齐数是4,所以要放在偏移量是4(偏移是相对结构体变量的地址,这一点要分清楚,所以嵌套结构体放任意位置占用大小不变)的整数倍上,往后占用4个字节,第三个成员变量是字符类型,大小为一个字节,任何整数都是1的倍数,所以第三个结构体成员紧跟着放在偏移量为8的位置上,此时我们从图片可以看到1到3的内存未被占用,但还是算入大小之中,此时结构体已经使用了9个字节,最后要看规则3,结构体总大小是最大对齐数(本例题中最大为4)的整数倍,所以我们要把9到11(也就是橙色区域)也划入结构体,故结果为十二字节大小。
struct S4
{
char c1;
struct S1 s1;
};
printf("%d\n", sizeof(struct S4));
这个结构体内部还嵌套了个结构体,此时s1要存储的位置的偏移量应该是结构体S1最大对齐数的整数倍,也就是4的整数倍处,而这个s1的大小我们已经算出是12字节,所以综合起前面的0到3的空间,共占用16字节。
注:数组的对齐数看数组元素的对齐数
为什么存在内存对齐?
大部分的参考资料都是如是说的:
1.平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
定类型的数据,否则抛出硬件异常。(这些估计我要到实际工作中才好理解)