C语言当中有一部分类型是自定义类型,比如结构体、数组、枚举、联合,其实指针也是自定义类型,我们可以定义各种各样类型的指针,这在我之前的文章中有指针的解析。本文着重于讲解结构体类型,以及它的一个重要特征------内存对齐
一.结构体的声明
下面是一个描述学生的结构体声明:
struct Stu
{
char name[20];
int age;
char sex[5];
char id[20]; //学号
};
可以用typedef来声名结构体(更加方便):
typedef struct Stu //这里的Stu完全可以省去,省去后更加简洁
{
char name[20];
int age;
char sex[5];
}Stu;
int main()
{
Stu student; //这里就不用再 :struct Stu student;
return 0;
}
记住:
1. 末尾务必要加分号;
2.Stu为结构体类型名称,而不是结构体变量名;
3.Stu可以省略,同时声明时就定义的结构体叫匿名结构体;但是不建议这样做,意义不大;
4.可以在声名结构体的时候就定义一个结构体变量,但是也不建议这样做,因为结构体声名是在main函数之外,这样在这里定义的结构体变量将会是一个全局变量,我们应该尽量避免使用全局变量;
注意1:两个结构体类型即使成员一模一样,它们也是两个截然不同的结构体,例如下面代码:
#include<stdio.h>
struct
{
char name[20];
int age;
char sex[5];
}x;
struct
{
char name[20];
int age;
char sex[5];
}a[10], *p;
int main()
{
p = &x;
return 0;
}
这里会有警告:“=”: 从“*”到“*”的类型不兼容
从而说明上面两个结构体虽然成员一模一样,但这两个结构体并不等同;
注意2:结构体的自引用
在结构体中包含一个类型为该结构本身的成员能不能行?
答案是:不可行。这样会形成死递归;
正确引用方式为引用一个结构体指针;
二.结构体变量的定义和初始化
上面其实就介绍到了结构体变量的定义了,我们要区分开来结构体类型名和结构体变量名。
下面来简单说说结构体的初始化,下面直接上一段示例代码:
typedef struct
{
char name[20];
int age;
char sex[5];
}Stu;
int main()
{
Stu student = {"wangmazi", 10, 'man'};
printf("%s", student.name);
return 0;
}
结构体初始化还有其他几种方法,都大同小异,就不再一一列举了。
三.结构体内存对齐(计算结构体的大小)
一:为什么存在内存对齐:
下面呈上一些收集来的官方语言:
1.平台原因(移植原因):不是所有的硬件平台都能任意访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常;
2.性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理 器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
总结出结构体内存对齐的最大意义:这是拿空间来换取效率(时间)的做法;
这样做究竟值不值呢?毋庸置疑,肯定值得的;
二:如何计算结构体大小(内存对齐规则)
我们要计算一个结构体大小就是它的每个成员大小相加的总和吗?
当然不是,这里就必须要先掌握结构体内存对齐的规则:
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 (VS中默认的值为8 ,Linux中的默认值为4)
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
注意:(可用 #pragma pack(NUM) 语句来将默认对其数修改为NUM )
下面举一个计算结构体大小的例子:
#include<stdio.h>
typedef struct
{
double d;
char c;
int i;
}S1;
typedef struct
{
char c1;
S1 s1; //一个结构体的对齐数为它内部的最大对齐数
double d;
}S2;
int main()
{
printf("%d\n", sizeof(S1)); //16
printf("%d\n", sizeof(S2)); //32
return 0;
}
注意我在其中的注释:一个结构体的对齐数为它内部的最大对齐数
四:结构体传参
结构体传参切记一点:用结构体指针传参
如果一个结构体过大,用结构体传参的话将会拷贝一份一模一样的结构体,会造成资源浪费,更重要的是时间效率严重下降
所以遇到结构体传参毫不犹豫选择结构体指针传参。