C语言自定义类型解析----结构体

      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   )

扫描二维码关注公众号,回复: 4714498 查看本文章

下面举一个计算结构体大小的例子:

#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;
}

注意我在其中的注释:一个结构体的对齐数为它内部的最大对齐数

四:结构体传参

结构体传参切记一点:用结构体指针传参
如果一个结构体过大,用结构体传参的话将会拷贝一份一模一样的结构体,会造成资源浪费,更重要的是时间效率严重下降
所以遇到结构体传参毫不犹豫选择结构体指针传参






 

猜你喜欢

转载自blog.csdn.net/eternal_yangyun/article/details/84568113