【C语言_结构体详解】

1、结构体类型的设计

C 语言提供了基本数据类型,如 char , short , int , float …等类型,我们称之为内置类型。程序开发人员可以使用结构体来封装一些属性,设计出新的类型,在 C 语言中称为结构体类型。

结构体类型的设计:

在 C 语言中,结构体是一种数据类型。(由程序开发者自己设计的类型)

可以使用结构体(struct)来存放一组不同类型的数据。结构体的定义形式为:

struct //结构体名
{ 
 ...  //成员列表(可以是基本数据类型,指针,数组或其它结构类型) 
};
1.1、 我们自己设计一个学生类型
  • 客观事物(实体)是复杂的,要描述它必须从多方面进行,也就是用不同的数据类型来描述不同的方面。如学生实体可以这样来描述:
  • 学生学号(用字符串描述),学生姓名(用字符串描述),性别(用字符串描述),年龄(用整型数描述)。
    这里用了属于 2 种不同数据类型,以及四个数据成员(data member)来描述学生实体。
    图示:
    在这里插入图片描述

2、结构体变量的定义和初始化

既然结构体是一种数据类型,那么就可以用它来定义变量。结构体就像一个“模板”,定义出来的变量都具有相同的性质。也可以将结构体比作“图纸”,将结构体变量比作“零件”,根据同一张图纸生产出来的零件的特性都是一样的。

结构体是一种数据类型,是创建变量的模板,不占用内存空间;结构体变量才包含了实实在在的数据,
需要内存空间来存储。

2.1 、结构体变量在内存中表示(不考虑内存对齐的问题,后面会讲解)

示例:

在这里插入图片描述

2.2、结构变量初始化

在这里插入图片描述

2.3、结构体嵌套结构体

示例:

#include<stdio.h>
typedef struct Date
{
	int year;
	int month;
	int day;
}Date;
struct Student
{
	char s_name[20];	//姓名
	Date birthday;		//生日
	float score;		//成绩
};
int main()
{
	struct Student stud1 = { "A",2001,1,1,99.5 };
	struct Student stud2 = { "B",{2002,2,2},88.5 };
	Date date;
	return 0;
 }
2.4、结构体自定义:

示例:

struct Student
{
	char s_name[8];
	int s_age;
	float score;
	struct Student studx;
};

示例:

struct Student
{
	char s_name[8];
	int s_age;
	float score;
//struct Student studx;	
	struct Student* next;
}

3、结构体成员访问(获取和赋值)

  • 结构体变量的成员使用 . 访问。
  • 获取和赋值结构体变量成员的一般格式为:
    • 结构体变量 . 成员名;
3.1、结构体变量成员的访问
#include<stdio.h> 
#include<string.h>
struct Inventory			// 商品
{
	char description[20];	// 货物名
	int quantity;			// 库存数据
};
int main()
{
	struct Inventory sta = { "iphone",20 };		// 1
	struct Inventory stb = sta;					// ok; // 2
	//struct Inventory& stc = sta;				//C语言 error //C++中ok; 引用
	struct Inventory std;						// 未初始化
	char name[20] = { 0 };
	int num = 0;
	printf("%s %d \n", sta.description, sta.quantity);
	 num = stb.quantity;						// ok;
	//name = stc.description;					// error;
	strcpy(name, stb.description);				// ok;
	//stc.description ="auto";					// error;
	strcpy(stb.description, "auto");			// ok
	stb.quantity = 100;							// ok
	std = sta;									// ok; // 3
	printf("%s %d \n", std.description, std.quantity);
	return 0;
}

注意:

对结构变量整体赋值有三种情况 (?)

  1. 定义结构体变量(用{ } 初始化),
  2. 用已定义的结构变量初始化,
  3. 结构体类型相同的变量可以作为整体相互赋值。

在其他情况的使用过程中只能对成员逐一赋值。
在 c 语言中不存在对结构体类型的强制转换(和内置类型的区别)。

3.2、结构体变量和指针
  • 内置类型能够定义指针变量,结构体类型也可以定义结构体类型指针。
  • 结构体类型指针访问成员的获取和赋值形式:
 (*p). 成员名 ( . 的优先级高于 *, (*p) 两边的括号不能少) 
 或
p -> 成员名 (->是 减号加大于号,中间没有空格,称为指向符) 

示例:
在这里插入图片描述

3.3、结构体变量和函数

示例 1:
在这里插入图片描述
示例 2:
在这里插入图片描述

4、结构体与数组

所谓结构体数组,是指数组中的每个元素都是一个结构体。在实际应用中,C 语言结构体数组常被用来表示一个拥有相同数据结构的群体,比如一个班的学生、一个公司的员工等。

示例

#include<stdio.h>
#include<string.h>
struct Student
{
	char s_name[20]; //姓名
	int age; //年龄
	float score; //成绩
};
int main()
{
	struct Student cla[] =
	{
		{"Tu lun", 18, 145.5 },
		{"Cheng Lei", 20, 130.5 },
		{"Wang ling", 19, 140.0 },
		{"Zhang pint", 17, 134.5 },
		{"Yang yang", 19, 135.0 },
		{"Hu Ming", 18, 140.0 },
	};
	return 0;
}

5、结构体大小

示例:
在这里插入图片描述

5.1、如何计算结构体的大小?

由于存储变量地址对齐的问题,计算结构体大小的 3 条规则:

  1. 结构体变量的首地址,必须是结构体变量中的“最大基本数据类型成员所占字节数”的整数倍。
  2. 结构体变量中的每个成员相对于结构体首地址的偏移量,都是该成员基本数据类型所占字节数的整数倍。
  3. 结构体变量的总大小,为结构体变量中 “最大基本数据类型成员所占字节数”的整数倍。

示例:假设是从 0 地址开始

在这里插入图片描述

5.2、总结

为什么要理解字节对齐问题。
1)内存大小的基本单位是字节(byte),理论上来讲,可以从任意地址访问变量,但是实际上,cup 并非逐字节读写内存,而是以 2,4,或 8 的倍数的字节块来读写内存,因此就会对基本数据类型的地址作出一些限制,即它的地址必须是 2,4 或 8 的倍数。那么就要求各种数据类型按照一定的规则在空间上排列,这就是对齐。
2)有些平台每次读都是从偶地址开始,如果一个 int 型(假设为 32 位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这 32bit,而如果存放在奇地址开始的地方,就需要 2 个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该 32bit 数据。显然在读取效率上下降很多。
3)由于不同平台对齐方式可能不同,如此一来,同样的结构在不同的平台其大小可能不同,在无意识的情况下,互相发送的数据可能出现错乱,甚至引发严重的问题。

5.4、指定对齐值

预处理指令#pragma pack(n) 可以改变默认对齐数。n 取值是 1, 2, 4, 8 , 16。

vs 中默认值 = 8,gcc 中默认值 = 4;

#pragma pack(1)
struct node
{
	char cha;
	int ia;
	short sa;
};
#pragma pack	//#pragma pack(n) 需要以 #pragma pack()作结束,表示该种对齐方式至此为止。

sizeof(struct node); //?

#pragma pack(2)
 struct node
 {
	char cha;
	int ia;
	short sa;
};
#pragma pack

sizeof(struct node); //?

#pragma pack(4)
 struct node
 {
	char cha;
	int ia;
	short sa;
};
 #pragma pack

 sizeof(struct node); //?

 #pragma pack(8)
 struct node
 {
	char cha;
	int ia;
	short sa;
};
 #pragma pack

 sizeof(struct node); //?

总结:

  1. 结构体变量的首地址,必须是 MIN{“结构体最大基本数据类型成员所占字节数”, 指定对齐方式} 大小的整数倍。
  2. 结构体每个成员相对于结构体首地址的偏移量,都是 MIN{基本数据类型成员, 指定对齐方式}大小的整数倍。
  3. 结构体的总大小,为 MIN{ 结构体 “最最大基本数据类型成员所占字节数”(将嵌套结构体里的基本类型也算上,得出最大基本数据类型成员所占字节数), 指定对齐方式} 大小的整数倍。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
引用\[1\]:C语言字节对齐问题详解中提到了C语言中的字节对齐问题。在结构中,为了提高内存访问的效率,编译器会对结构进行字节对齐。这意味着结构的成员在内存中并不是紧凑排列的,而是按照一定的规则进行对齐。具的对齐规则取决于编译器和编译选项。\[1\] 引用\[2\]:在C语言中,可以使用宏offsetof来获取结构成员相对于结构开头的字节偏移量。这个宏非常有用,可以帮助我们计算出每个结构成员相对于结构开头的偏移字节数。通过这个宏,我们可以更好地理解结构的内存布局。\[2\] 引用\[3\]:在C语言中,指针和结构的组合常常用于处理复杂的数据结构。指针可以指向结构的成员,通过指针可以方便地对结构进行操作。指针和结构的组合可以实现更灵活的数据处理和内存管理。\[3\] 综上所述,C语言中的指针结构组合可以用于处理复杂的数据结构,而字节对齐问题则是在结构中为了提高内存访问效率而进行的优化。通过使用宏offsetof,我们可以更好地理解结构的内存布局。 #### 引用[.reference_title] - *1* *3* [结构指针,C语言结构指针详解](https://blog.csdn.net/weixin_34069265/article/details/117110735)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [C语言结构详解](https://blog.csdn.net/m0_70749276/article/details/127061692)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千北@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值