C语言:结构体,联合体


一、结构体

结构体是一组元素类型不同的元素的集合

1.结构体的声明和结构体变量的定义

结构体的声明包含三个部分,标记名(tag),成员列表(member-list),变量列表(variable-list)。
假如我们要声明一个学生类型,如下:
在这里插入图片描述
如果我们要定义变量,我们有两种方式。

  • 用结构体类型直接定义变量
  • 在变量列表中定义变量

如下:

//在变量列表中定义变量s1,s2
struct Student
{
    
    
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
	char id[20];//学号
}s1; s2;


int main()
{
    
    
	//使用结构体类型定义变量s3
	struct Student s3;

	return 0;
}

除此外,我们也可以是匿名声明(不完全声明),如下:

//不完全声明
struct
{
    
    
	char c;
	short b;
	int a;
};

在此情况下,我们要定义变量,只能在变量列表中定义,因为我们并不知道该结构体的类型。
如下:

//定义变量s1,s2,s3
struct
{
    
    
	char c;
	short b;
	int a;
}s1; s2; s3;

如果我们不完全声明两个完全相同的结构体,编译器会认为这两个结构体的类型不同。
如下:

//定义变量s1,s2,s3
struct
{
    
    
	char c;
	short b;
	int a;
}s1; s2; s3;

//定义指针ps
struct
{
    
    
	char c;
	short b;
	int a;
}*ps;

int main()
{
    
    
	ps = &s1;

	return 0;
}

在这里插入图片描述

2.结构体变量初始化

对于结构体变量的初始化,有两种方式。

  1. 可以在变量列表中初始化变量
struct Student
{
    
    
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
	char id[20];//学号
}s1 = {
    
     "李四", 20, "男", "123456" };
  1. 用类型定义时,初始化变量
struct Student
{
    
    
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
	char id[20];//学号
};

int main()
{
    
    
	struct Student s1 = {
    
     "李四", 20, "男", 123456 };

	return 0;
}

3. 访问结构体成员

对于结构体变量访问其成员,我们用 . 操作符进行访问。
对于结构体指针变量访问其所指向的成员,我们用 -> 操作法进行访问。
如下:

struct A
{
    
    
	char a;
	int b;
};

int main()
{
    
    
	struct A a = {
    
     0 };
	struct A* pa = &a;

	a.b = 10;
	printf("%d\n", a.b);

	pa->b = 20;
	printf("%d\n", pa->b);

	return 0;
}

结果如下:
在这里插入图片描述

4.结构体的内存对齐

要介绍结构体的内存对齐,就不得不计算结构体的大小了。
如下结构体的大小是什么?

struct A
{
    
    
	char a;
	int b;
	char c;
};

int main()
{
    
    
	printf("%d\n", sizeof(struct A));
	return 0;
}

答案是12,这就是因为结构体要内存对齐。
想要知道12是如何计算的,我们就要掌握关于对齐数的相关规则。

  • 第一个结构体成员永远在地址偏移量为0处。
  • 其它成员变量要对齐到它的对齐数的整数倍的地址处
  • 结构体的总大小为最大对齐数(其成员变量的对齐数)的整数倍
  • 如果嵌套了结构体,嵌套的结构体对齐到字节的最大对齐数的整数倍处,结构体的整体大小就是最大对齐数(嵌套的结构体也是该结构体的成员)的整数倍

对齐数 = 编译器默认的对齐数 与 该成员的大小的较小值。如果编译器没有默认对齐数,那么对齐数就是成员本身的大小。

在这里插入图片描述
至此,我们就知道12是如何得到。但为什么要有内存对齐?

  1. 平台原因(移植原因)
    不是所有的硬件平台都能访问任意地址上的任意数据;某些硬件平台只能在某些地址处取某些特 定类型的数据。

  2. 性能原因
    数据结构(尤其是栈)应该尽可能的在自然边界上对齐。
    为了访问未对齐的内存大小,处理器需要做两次内存访问;而对齐的内存访问仅需要一次访问。

二、联合(共用体)

共用体顾名思义就是该类型的成员使用同一块内存空间。
如下:
声明联合体类型union A,其成员是 char a,int b。

union A
{
    
    
	char a;
	int b;
};

那么其大小是多少?

union A
{
    
    
	char a;
	int b;
};

int main()
{
    
    
	printf("%d\n", sizeof(union A));

	return 0;
}

答案是4,为什么?

  1. 联合体的大小至少是其最大成员的大小
  2. 联合体的大小还要是其对齐数的整数倍

在这里插入图片描述
如上图所述,其成员a和b公用第一个字节,如果我们在使用成员a时,一起使用成员b,那么a = 多少?

union A
{
    
    
	char a;
	int b;
};


int main()
{
    
    
	union A un = {
    
     0 };
	un.a = 1;
	un.b = 10;

	printf("%d\n", un.a);

	return 0;
}

答案是a = 10。我们只需要看内存的变化即可。
在这里插入图片描述


总结

以上就是我对于结构体,在这里插入图片描述
联合体知识的总结。

猜你喜欢

转载自blog.csdn.net/li209779/article/details/131889487