C语言结构体总结(包括结构体内存对齐)

本文详细介绍了结构体在C语言中的概念,包括结构体类型定义、结构体变量的创建和赋值,以及结构体数组、指针和作为函数参数的应用。重点讲述了内存对齐的原则及其在实际代码中的体现。
摘要由CSDN通过智能技术生成

结构体的介绍和定义

1.基本概念

   结构体是一种构造类型,有若干数据组成,这些数据叫做结构体成员。其中 ,每一个结构体成员都是一种基本数据类型或者结构类型。它的作用就相当于给数据分类并调用,把一个对象的多种元素封装到一个区域内。比如说构成一个人的元素有姓名,年龄,性别等。

2.结构体类型定义

struct  结构体类型名

{

   结构体成员

};

struct是结构体定义的关键字,不能省略。

结构体类型名用来与其他结构体类型区分,它一般是以结构体成员共同指向的内容来命名,命名是有意义的

如:

stuct person
{
   int age;
   char name [20]
};

在定义了结构体之后,它不会被分配实际内存。因为它就相当于你定义了一个规则,之后你创建的结构体变量就适用这个规则。只有在创建了结构体变量之后 ,结构体变量才会被分配实际内存。总而言之,结构体的定义是为结构体变量的创建服务的

结构体变量的定义和赋值

1.结构体变量的定义方法

a.先定义类型,后定义变量
struct person
{
  int age;
  char name[20];
};
stuct person zhangsan;

其中,zhangsan就是一个结构体变量,其内容是age和name。

b.同时定义类型和变量(较为常用)
struct person
{
  int age;
  char name[20];
};zhangsan;

这种定义方式较为简洁

c.匿名结构体变量
struct
{
 int age;
 char name[20];
}zhangsan;

这种结构体变量较为特殊,它省略了结构体类型名而直接定义变量。这种匿名结构体变量只能被引用一次,属于临时变量。

2.结构体变量的赋值和引用

继续以上面的例子为例进行赋值操作

struct person
{
  int age;
  char sex[20];
};zhangsan={18,"male"};

注意:赋值时,要按照结构体定义的顺序进行。否则,就需要 “.” 操作符明确表示给哪个成员赋值,如下:

struct person
{
  int age;
  char sex[20];
};zhangsan;
zhangsan.sex="male";
zhangsan.age=18;

结构体数组和指针

结构体数组的定义

struct stu
{
 char name[20];
 char sex[20];
 int age;
}student={{"zhangsan","male",18},{"lisi","male",19},{"wangwu","female",20}};

结构体指针的定义

struct stu
{
  char name[20];
  int age;
};student1,*p;
p=&student1;

结构体指针引用结构体内容,需要 “->” 如:

p->age;
p->name;
//或者
(*p).name;
(*p).age;
//其中的括号不能省略,因为“.”运算符的优先级更高

结构体作函数的参数

a.结构体变量成员作函数的参数
fun(studeng1.name,student1.age);
//直接把结构体成员的值作为参数传给函数即可
b.结构体变量作函数的参数
struct stu
{
 char name[20];
 int age;
}x;
//创建结构体变量X

fun(x);
//传实参

void fun(struct stu y)
//设形参

深挖,结构体的内存对齐原则

这里我给出下面一段代码

#include <stdio.h>
int main()
{
	struct stu
	{
		char name[2];
		short age;
		int weight;
	}a;
	struct stu2
	{
		short age;
		int weight;
		char name[2];
	}b;

	int ret = sizeof(a);
	int ret2 = sizeof(b);
	printf("%d\n", ret);
	printf("%d\n", ret2);
//分别求出两个结构体的字节大小
	return 0;
}

代码输出的结果是

明明两个结构体的内容相同,都是一个短整型,一个整型,和两个字符型,理论上两个结构体的内存占用应该都是8个字节才对,可为什么有一个结构体的内存字节大小为12呢?这是因为结构体内存分配遵循对齐原则。

我们不难发现,两个结构体中的成员虽然一样,但它们的顺序略有不同。而结构体分配内存会从前向后分配。按正常情况的话,应该会像图中这样

而这也确实是结构体变量a的内存存储方式

通过下面的对齐规则,我们就可以分析上述问题了

a的分析过程

a变量中,char型的name有两个数据,对齐数都是1,直接就分到两个连续的内存。

short型的age,对齐数是2,那么它分配到的地址偏移值得是2的倍数,2处正好满足。偏移值2到3,就存放了age。

int型的weight,对齐数是4,那么它分配到的地址偏移值得是4的倍数,4处正好满足。偏移值4到7,就存放了age。

a的总大小如图可知为8个字节

但变量b的存储方式跟a有所差别(空白处是浪费掉的内存)

b的分析过程

b变量中,short型的age占两个字节,从偏移值0到1.

int型的weight对齐数是4,那么它分配到的地址偏移值得是4的倍数,显然2和3不是4的倍数,这两个空间就要浪费掉,那么weight就从偏移值为4的地址开始向后分配空间,偏移值从4到7。

char型的name有两个数据,对齐数都是1,直接就跟在weight的后面分到两个连续的内存,偏移值8到9。

最后,b中的最大对齐数是int的4,所以总大小也得是4的倍数,但目前的大小只有10字节,所以就补偏移值10和11的空间,补到12个字节大小。

b的总大小由图可知为12

对齐规则:

1.从第一个数据类型起,会先在偏移值为0处占用空间。

2.从第二个数据类型开始,他要对齐某个数整数倍的地址处。这个数我们称为对齐数

对齐数=改编译器默认的对齐数和数据大小(字节)的较小值

其中,不同编译器的默认对齐数是不同的,vs的是8。

3.结构体的总大小为最大对齐数(包括了数组中的元素)的整数倍数

4.如果结构体还相互嵌套了,那么结构体的总大小也满足3.的条件,其中包括了嵌套结构体中的各个元素

  • 17
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值