自定义类型——结构体类型

本篇将讲解结构体的基本知识,及其的注意点和基本使用


目录

结构体

 结构体定义

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

结构访问操作符

结构体内存对齐(计算结构体大小)

内存对齐存在原因

修改默认对齐数


结构体

结构体是一种自定义类型的数据,数组也是一种自定义类型,可以用数组作类比理解结构体,不过数组里的成员只能定义个数和类型,而结构体内可以定义任意类型的成员,也就是结构体内可以装任意类型的数据,并且这些数据可以是不同类型的

结构体的关键字是 struct


 结构体定义

struct tag

{

member-list;

}variable-list;

tag 是自己写的一个标签(用来表示这个结构体是关于什么的)结构体类型就为 strcut tag

tmamber-list 是成员列表,括号里就是结构体里包含哪些类型的数据(注意:这里只是在定义结构体是怎么样的,只需要声明它有哪些类型的数据,不需要给这些数据创建变量

variable-list 是在定义结构体时顺便也创建类型为这个结构体的变量,可以一次性创建多个,在这里创建是则创建的一个全局变量,当然也可以在其他地方创建

注意:结构体定义最后面的 ' ; ' 号不可以省略

特殊的声明的结构体:省略掉标签(tag),此为匿名结构体,若没有对此结构体类型重命名的话基本上只能使用一次

例:

struct student  - 定义一个关于学生信息的结构体,信息包含学生的年龄、名字、学号
{
    int age;
    char name[50];
    int ID;
}a,b,c;  - 并创建三个类型为 struct student 的变量

int main()
{
    struct student d;  - 再创建一个局部变量 d
}


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

像上面所说, 定义中 variable-lsit 就是变量的创建,且为全局变量

其他变量定义:struct tag(类型) s1(变量名) = {};放函数里即为局部变量,s1 即是一个变量,类型为 struct tag

变量的初始化分两种:默认顺序初始化 和 指定顺序初始化

例:

struct student 
{
    int age;
    char name[50];
    int ID;
}a = {17, "zhangsan", 101},b,c;  - 创建全局结构体变量 a 的同时并将它按默认顺序初始化  

int main()
{
    struct student d = { .ID = 103, .age = 20, .name = "lisi"};  - 按我们自己指定的顺序初始化
}

结构访问操作符

 点操作符:.

箭头操作符:-> (由一个减号(-) 和 大于符号(>) 组成)

作用:

 直接访问:结构体成员的直接访问是通过点操作符(.)访问

点操作符接受两个操作数 —— 结构体变量 . 成员名

间接访问:结构体指针 -> 成员名

例:

struct student  
{
    int age;
    char name[50];
    int ID;
}a,b,c;  

int main()
{
    struct student d; 
    stuct student* pd = &d;  - 创建指针变量 pd,并取出 d 的地址赋值给 pd
    pd->age = 17;  - 指针 pd 通过箭头操作符访问其指向的结构体变量的成员 age,并赋值 17
    d.name = "头发化码";  - 变量 a 通过点操作符访问其成员 name,并赋值 头发化码
}

通过上面的例子,你一定对结构访问操作符有一定理解了,不过其实这个例子里面有个地方是错误的,这也是使用结构访问操作符需要注意的一个小细节,具体如下

 在之前变量的定义和初始化中,我举了一个这样的例子:
struct student d = { .ID = 103, .age = 20, .name = "lisi"};  - 这段代码是没问题的

刚刚上面的例子中又有这样一段代码:
d.name = "头发化码";  - 其实这段代码是错误的

注意 .name = "lisi" 和 d.name,为什么前面一个是对的,而后面一个是错误的呢,这里并不是因为 . 前面有差异而导致错误的,而是两段代码所处位置导致含义的不同,前者是在创建结构体变量的同时将结构体的成员初始化,这时这些结构体成员里的值就是这些初始值,而后者是通过点操作符访问到 name 这个成员,而 name 是一个数组,它在这里表示的是首元素地址,首先它是指针常量,是不可以赋值的,其次就算能赋值,也不能达成我们想要的效果,因为他只是一个地址,而不是我们想要的地址内的空间

当然,这个注意点只针对数组成员,因为其他类型数据的变量名在不同地方表示的含义是相同的,只有数组的变量名是要分情况确定它的含义,想具体了解的小伙伴可以点击我看”数组名“的内容


结构体内存对齐(计算结构体大小)

 结构体是存在一个叫内存对齐的规则的,它规定了结构体内的成员是如何分配空间的,并决定了整个结构体的大小

在讲解对齐规则前先补充一个对齐数的知识

对齐数 = 编译器默认的一个对齐数与该成员变量大小的较小值(VS 中默认为 8,Linux 中 gcc 没有默认对齐数,对齐数就是成员自身大小),比如一个 int a,它的大小为 4(字节),在 VS 当中默认对齐数为 8,4 < 8,所以成员 a 的对齐数为 4

 对齐规则:

1.结构体的第一个成员对齐到结构体起始位置偏移量为 0 的地址处

2.其他成员对齐到其对齐数的整数倍的地址处

3.结构体总大小为最大对齐数(这个结构体所有成员中最大的)的整数倍

4.若嵌套了结构体,这个嵌套的结构体成员的对齐数为其自己成员中的最大对齐数

这里我们举两个例子:

                                                                例一

                                                                例二  


内存对齐存在原因

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

2.性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐,因为对于未对齐的内存,处理器需要进行两次内存访问。例:假设一个处理器总是从内存中取 8 个字节,也就是处理器是按 8 个字节的内存一块一块处理的,若一个数据分布在两个块中,处理器则需要取出这两个块才能取出这个数据

总体来说:结构体内存对齐是拿空间换取时间的做法


修改默认对齐数 

预处理命令:#pragma pack()

修改默认对齐数为括号里的数,若不填则还原为默认对齐数


最后,这里再附上其他几个自定义数据类型 :

联合体类型与枚举类型

数组

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据预处理中的自定义转换是指将数据集中的原始数据按照一定的规则进行处理,以便于后续的模型训练和应用。C++作为一门强类型语言,提供了丰富的数据类型和操作函数,可以非常方便地实现数据预处理中的自定义转换。下面以一个简单的案例来演示如何使用C++实现数据预处理中的自定义转换。 假设我们有一个包含学生信息的数据集,其中每个学生的信息包括姓名、年龄、性别与成绩四个属性。现在我们要对这个数据集进行处理,将每个学生的成绩按照以下规则转换为一个0~5的整数: - 小于60分的成绩转换为0 - 60~69分的成绩转换为1 - 70~79分的成绩转换为2 - 80~89分的成绩转换为3 - 90~99分的成绩转换为4 - 100分的成绩转换为5 下面是一个使用C++实现的解决方案: ```c++ #include <iostream> #include <vector> #include <string> using namespace std; // 定义一个结构体,表示学生信息 struct Student { string name; int age; char gender; int score; }; // 自定义转换函数,将成绩转换为0~5的整数 int score_transform(int score) { if (score < 60) { return 0; } else if (score < 70) { return 1; } else if (score < 80) { return 2; } else if (score < 90) { return 3; } else if (score < 100) { return 4; } else { return 5; } } int main() { // 定义一个学生信息列表 vector<Student> students = { {"张三", 18, 'M', 75}, {"李四", 19, 'F', 68}, {"王五", 20, 'M', 92}, {"赵六", 21, 'F', 85} }; // 遍历学生信息列表,将成绩转换为整数 for (auto& student : students) { student.score = score_transform(student.score); } // 输出转换后的学生信息列表 for (auto& student : students) { cout << student.name << " " << student.age << " " << student.gender << " " << student.score << endl; } return 0; } ``` 在上面的代码中,我们首先定义了一个包含学生信息的结构体`Student`,并且定义了一个自定义转换函数`score_transform`,用于将成绩转换为整数。然后我们定义了一个学生信息列表`students`,并且遍历该列表,将每个学生的成绩按照自定义转换函数进行转换。最后我们输出转换后的学生信息列表。 需要注意的是,在实际应用中,我们可能需要进行更加复杂的自定义转换,例如对数据进行归一化、标准化、降维等处理。C++提供了丰富的函数库和工具,可以帮助我们实现这些复杂的自定义转换。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值