C++ 关于结构体struct的一些总结

文章目录

    • 一、 结构体(struct)是什么?
      • (1)概念
      • (2)struct 与 calss 的区别
    • 二、定义、声明与初始化
      • (1)三种定义结构体的方法:
      • (2)结构体变量初始化
    • 三、结构体嵌套
    • 四、结构体数组
    • 五、结构体指针
    • 六、结构体指针成员
      • (1)指向文字常量区:
      • (2)指向堆区:
    • 七、结构体的拷贝
      • (1)浅拷贝
      • (2)深拷贝
    • 八、返回值是结构体的函数
    • 九、结构体的对齐规则
      • (1) 为什么要对齐
      • (2)强制对齐规则
      • (3)有趣的问答
    • 九、共用体 union
    • 十、枚举 enum

一、 结构体(struct)是什么?

(1)概念

  • 结构体是一种自定义的数据类型,它可以包含多个不同的数据类型的成员。结构体允许用户将相关的数据项组合在一起形成一个单独的实体,并可以对该实体进行操作。
  • C++中结构体和类基本完全类似!C++中结构体能继承、能实现多态!结构体中也可以包含构造函数和析构函数和其他内部成员函数,因此结构体和类基本雷同!唯一的区别是,类中的成员变量默认为私有,而结构体中则为公有。
  • struct更适合作为数据结构的实现体,class更适合作为对象的实现体。

(2)struct 与 calss 的区别

概念:class和struct的语法基本相同,从声明到使用,都很相似,但是struct的约束要比class多,理论上,struct能做到的class都能做到,但class能做到的stuct却不一定做的到
类型:struct是类型,class是引用类型,因此它们具有所有值类型和引用类型之间的差异
效率:由于堆栈的执行效率要比堆的执行效率高,但是堆栈资源却很有限,不适合处理逻辑复杂的大对象,因此struct常用来处理作为基类型对待的小对象,而class来处理某个商业逻辑
关系:struct不仅能继承也能被继承 ,而且可以实现接口,不过Class可以完全扩展。内部结构有区别,struct只能添加带参的构造函数,不能使用abstract和protected等修饰符,不能初始化实例字段

应用场景

(1) 在表示诸如点、矩形等主要用来存储数据的轻量级对象时,首选struct

(2) 在表示数据量大、逻辑复杂的大对象时,首选class

(3) 在表现抽象和多级别的对象层次时,class是最佳选择

二、定义、声明与初始化

  • 系统不会为结构体类型开辟空间,只会为结构体类型定义的变量开辟空间
  • 不能在结构体声明中初始化结构体成员,因为结构体声明只是创建一个新的数据类型,还不存在这种类型的变量。
  • 默认情况下,所有结构体成员都是公开的,所以不需要使用关键字 public

(1)三种定义结构体的方法:

1.先定义结构体类型,再定义结构体变量。

struct Student
{int Code;string Name;
};
Student tom;

2.定义结构体类型的同时定义变量。

struct Student{int Code;string Name;
} tom;

3。定义一次性结构体类型。

struct{int Code;string Name;
} tom;

(2)结构体变量初始化

1.默认构造函数

struct Student
{int Code;string Name;
};
Student tom = {50, "tom"};

2.自定义构造函数

struct Student
{int Code;string Name;Student (int code, string name){Code = code;Name = name;}
};
Student tom = {50, "tom"};

三、结构体嵌套

一个类的对象可以嵌套在另一个类中一样,一个结构体的实例也可以嵌套在另一个结构体中。

#include <iostream>
#include <string>
using namespace std;struct Address
{string street;string city;string state;
};struct Person {string name;int age;Address address; // 结构体嵌套
}; int main() {Person person1 = { "John Doe", 30, { "123 Main St", "Anytown", "CA" } }; // 嵌套结构体的初始化赋值cout << "Name: " << person1.name << endl;cout << "Age: " << person1.age << endl;cout << "Address: " << person1.address.street << ", ";cout << person1.address.city << ", " << person1.address.state << endl;system("PAUSE");return 0;
}

四、结构体数组

结构体数组本质是数组,只是数组的每个元素是结构体变量

struct student {int id;char name[20];float score;
};int main() {// 定义一个有3个元素的结构体数组student stu[3];// 给每个学生赋值stu[0].id = 1;strcpy(stu[0].name, "Tom");stu[0].score = 90;stu[1].id = 2;strcpy(stu[1].name, "Jerry");stu[1].score = 80;stu[2].id = 3;strcpy(stu[2].name, "Bob");stu[2].score = 85;// 输出每个学生的信息for (int i = 0; i < 3; i++) {cout << "ID: " << stu[i].id << endl;cout << "Name: " << stu[i].name << endl;cout << "Score: " << stu[i].score << endl;cout << endl;}return 0;
}

五、结构体指针

  • 结构体指针变量本质是变量,只是该变量保存的是结构体变量的地址。
  • 在使用结构体指针时,要使用箭头运算符(->)来访问成员变量。因为指针本身只存储了地址信息,而不是结构体本身,所以需要使用箭头运算符来指示指针所指向的结构体中的成员变量。
struct student {int id;char name[20];float score;
};int main() {// 定义一个名为s的结构体变量student s;// 定义一个名为p的结构体指针变量,并将其指向sstudent *p = &s;// 通过指针访问结构体中的成员变量p->id = 1;strcpy(p->name, "Tom");p->score = 90;return 0;
}

六、结构体指针成员

(1)指向文字常量区:

struct Stu{int num;char *name;
};
struct Stu lucy={101,"hello world"};

在这里插入图片描述

(2)指向堆区:

struct Stu{int num;char *name;
};
struct Stu lucy;
lucy.name=new char[32];  // 指向堆区
lucy.num=101;
strcpy(lucy.name,"lucy");delete[] lucy.name;

七、结构体的拷贝

(1)浅拷贝

  • 相同类型的结构体变量可以整体赋值,默认方式是浅拷贝
  • 如果结构体中没有指针成员,浅拷贝不会带来任何问题。如果结构体中有指针成员,浅拷贝会带来多次释放堆区空间的问题。
#include <iostream>
#include <string>
using namespace std;struct Student {char* name;int age;
};int main() {Student s1 = { "Tom", 18 };Student s2 = s1; // 浅拷贝cout << "Befor: s1.name: " << s1.name << endl;cout << "Befor: s2.name: " << s2.name << endl;s1.name = "Jerry";cout << "After: s1.name: " << s1.name << endl;cout << "After: s2.name: " << s2.name << endl;system("PAUSE");return 0;
}

(2)深拷贝

  • 深拷贝是指复制一个新的对象,其中包含原始对象中所有成员变量的副本,而不是只简单地复制指向成员变量数据的指针。
  • 如果结构体中有指针成员,尽量使用深拷贝。

八、返回值是结构体的函数

可以从函数返回结构体变量。在这种情况下,函数的返回类型是结构体的名称。

#include <iostream>  
#include <string>  
using namespace std;struct Student {string name;int age;
};
Student getStudent()
{Student st;cout << "Enter the name:";cin.get();getline(cin, st.name);cout << "Enter the age ";cin >> st.age;return st;
}int main()
{Student stu = getStudent();cout << "name : " << stu.name << endl;cout << "age : " << stu.age << endl;system("PAUSE");return 0;
}

九、结构体的对齐规则

(1) 为什么要对齐

假设有这样一个结构体:

struct Data{char a;int b;
};

CPU一次读取4字节,当没有字节对齐时,内存状态:

img

  • 访问a只需要一个周期,读取四个字节,只用第一个字节,其他字节丢弃。
  • 访问b需要两个周期:第一个周期读取4字节,只要后三个字节;第二个周期读取4字节,只要第一个字节;然后将它们拼接成一个4字节的数据得到b。

CPU一次读取4字节,字节对齐时,内存状态:

img

  • 访问a只需要一个周期,读取四个字节,只用第一个字节,其他字节丢弃。
  • 访问b只需要一个周期,读取四个字节。

img

可以看到,字节对齐之后访问速度就变快了,而且不用进行字节拼接;只是需要浪费三个字节的空间(用空间换时间)。但是带来的好处是:提取快、方便、效率高。

(2)强制对齐规则

#pragma pack(value)
  • 基本类型的对齐值就是其sizeof值;
  • 结构体的对齐值是其成员的最大对齐值;
  • 指定对齐值value,value值一般为1、2、4、8、16等(2的n次幂)。
  • 编译器可以设置一个最大对齐值,怎么类型的实际对齐值是该类型的对齐值与默认对齐值取最小值得来。

(3)有趣的问答

问:现代Intel的CPU,不对齐并不会影响访问速度?

答:虽说如此,但是很多场景下我们对性能十分讲究,用的可能也不是Intel的CPU,比如一些嵌入式设备,又或者说游戏引擎开发,可谓是极尽性能之能事,这时候必须要小心翼翼,避免任何有可能影响存取速度的地方,以“榨干”机器的性能。

又比如,没有考虑内存对齐的时候,有些内存是“空着”的,也无法利用,这时候对于一些内存极小的设备来说,就必须要争取利用每一块可能的内存,避免空间浪费。

九、共用体 union

共用体(union)是一种特殊的数据类型,它允许在同一个内存区域存储不同的数据类型。这些成员并不是随意放置,而是用有相同的首地址。因此,我们在任意时刻只可以按照一个数据类型对共用体进行赋值,共用体中这些成员的关系是“或”,即“不是你死就是我活”。

其实我们可以这样说“共用体其实可以在任意时刻被当作其任意一个数据成员来赋值使用”。共用体的出现基本上实现了我们追求的“万能数据类型”。

union my_union {int i;float f;char str[10];
};

简单应用:

共用体的用途之一是,当数据项使用两种或更多种格式(但不会同时使用)时,可节省空间。例如,假设管理一个小商品目录,其中有一些商品ID为整数,而另一些的ID为字符串。在这种情况下,可以这样做。

struct widget
{char brand[20];int type;union id{long id_num;char id_char[20];}id_val;
};
...
widget prize;
...
if(prize.type == 1)cin>>prize.id_val.id_num;
elsecin>>prize.id_val.id_char;

十、枚举 enum

枚举(enum)是 C++ 中的一种数据类型,它允许将一组常量值定义为一个命名集合。枚举中的每个元素都有一个关联的整数值,默认情况下从 0 开始递增。枚举元素也可以显式地指定整数值。

enum EnumName {Element1,Element2 = 10,Element3
};

简单应用:

enum Color {Red,Green,Blue
};int main() {Color c = Red;if (c == Green) {std::cout << "Green\n";} else if (c == Blue) {std::cout << "Blue\n";} else if (c == Red) {std::cout << "Red\n";}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/208959.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++实现进程端口网络数据接收系统设计示例程序

一、问题描述 最近做了一道简单的系统设计题&#xff0c;大概描述如下&#xff1a; 1.一个进程可以绑定多个端口&#xff0c;用于监听接收网络中的数据&#xff0c;但是一个端口只能被一个进程占用 2.1 < pid < 65535, 1 < port < 100000, 1 < topNum < 5, …

ros2/ros安装ros-dep||rosdep init错误

第一个错误的做法&#xff1a; sudo apt-get install python3-pip sudo pip3 install 6-rosdep sudo 6-rosdep 如果使用上述代码将会摧毁整个系统&#xff0c;不重装系统反正我是搞不定啊&#xff0c;因为我不知道那个写软件的人到底做了什么。因为这个我安装的版本是humble&…

AlexNet 阅读笔记

“ImageNet Classification with Deep Convolutional Neural Networks” (Krizhevsky 等, 2012, p. 1) 使用深度卷积神经网络进行 ImageNet 分类 3公式&#xff0c;26个引用&#xff0c;4张图片&#xff0c;2个简单表格 Abstract 我们训练了一个大型深度卷积神经网络&#…

Leetcode刷题详解——环绕字符串中唯一的子字符串

1. 题目链接&#xff1a;467. 环绕字符串中唯一的子字符串 2. 题目描述&#xff1a; 定义字符串 base 为一个 "abcdefghijklmnopqrstuvwxyz" 无限环绕的字符串&#xff0c;所以 base 看起来是这样的&#xff1a; "...zabcdefghijklmnopqrstuvwxyzabcdefghijklm…

卷积之后通道数为什么变了

通道数增多与卷积之后得到的图像特征数量有关 卷积层的作用本来就是把输入中的特征分离出来变成新的 feature map&#xff0c;每一个输出通道就是一个卷积操作提取出来的一种特征。在此过程中ReLU激活起到过滤的作用&#xff0c;把负相关的特征点去掉&#xff0c;把正相关的留…

C++:vector增删查改模拟实现

C:vector增删查改模拟实现 前言一、迭代器1.1 非const迭代器&#xff1a;begin()、end()1.2 const迭代器&#xff1a;begin()、end() 二、构造函数、拷贝构造函数、赋值重载、析构函数模拟实现2.1 构造函数2.1.1 无参构造2.1.2 迭代器区间构造2.1.3 n个值构造 2.2 拷贝构造2.3 …

vue路由导航守卫(全局守卫、路由独享守卫、组件内守卫)

目录 一、什么是Vue路由导航守卫&#xff1f; 二、全局守卫 1、beforeEach 下面是一个beforeEach的示例代码&#xff1a; 2、beforeResolve 下面是一个beforeResolve的示例代码&#xff1a; 3、afterEach 下面是一个afterEach的示例代码&#xff1a; 三、路由独享守卫…

Shell - 学习笔记 - 1.14 - 如何编写自己的Shell配置文件(配置脚本)?

第1章 Shell基础(开胃菜) 14 - 如何编写自己的Shell配置文件(配置脚本)? 学习了《Shell配置文件的加载》一节,读者应该知道 Shell 在登录和非登录时都会加载哪些配置文件了。对于普通用户来说,也许 ~/.bashrc 才是最重要的文件,因为不管是否登录都会加载该文件。 我们…

【数据处理】NumPy数组的合并操作,如何将numpy数组进行合并?

&#xff0c;NumPy中的合并操作是指将两个或多个数组合并成一个数组的操作。这种操作可以通过不同的函数来实现。 一、横向合并&#xff08;水平合并&#xff09; 横向合并是指将两个具有相同行数的数组按列方向合并成一个数组的操作。在NumPy中&#xff0c;可以使用hstack()…

044:vue中引用json数据的方法

第044个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

多相Buck的工作原理

什么是多相Buck电源&#xff1f; 多相电源控制器是一种通过同时控制多个电源相位的设备&#xff0c;以提供稳定的电力供应。相位是指电源中的电流和电压波形。多相控制器的设计旨在最大程度地减小电力转换系统的纹波&#xff0c;并提高整体能效。它通常包含一系列的功率级联&a…

我的创作纪念日1024天纪念

机缘 经历的1024天&#xff0c;突然有一种惊奇&#xff0c;日子一天天过&#xff0c;有种恍惚的感觉 收获 从最开始的随笔&#xff0c;慢慢向着笔记总结转变&#xff0c;不经意间积累了好多 憧憬 虽不知最终会怎样发展&#xff0c;但坚持与向前是一定的&#xff0c;未来一…

结构化布线系统

满足下列需求&#xff1a; 1.标准化&#xff1a;国际、国家标准。 2.实用性&#xff1a;针对实际应用的需要和特点来建设系统。 3.先进性&#xff1a;采用国际最新技术。5-10年内技术不落后。 4.开放性&#xff1a;整个系统的开放性。 5.结构化、层次化&#xff1a;易于管理和维…

Matplotlib数据可视化

绘图基础语法 &#xff11; 创建画布并且创建子图 首先创建一个空白的画布&#xff0c;并且可以将画布分为几个部分&#xff0c;这样就可以在同一附图上绘制多个图像。 plt.figure 创建一个空白画布&#xff0c;可以指定画布大小、像素 figure.add_subplot 创建并且选中子…

docker镜像、容器管理与迁移

镜像管理 搜索镜像&#xff1a; 这种方法只能用于官方镜像库 搜索基于 centos 操作系统的镜像 # docker search centos 按星级搜索镜像&#xff1a; 查找 star 数至少为 100 的镜像&#xff0c;默认不加 s 选项找出所有相关 ubuntu 镜像&#xff1a; …

【web安全】文件读取与下载漏洞

前言 菜某整理仅供学习&#xff0c;有误请赐教。 概念 个人理解&#xff1a;就是我们下载一个文件会传入一个参数&#xff0c;但是我们可以修改参数&#xff0c;让他下载其他的文件。因为是下载文件&#xff0c;所以我们可以看到文件里面的源码&#xff0c;内容。 文件读取…

Python嗅探和解析网络数据包

网络工具解释 Scapy是Python2和Python3都支持的库。 它用于与网络上的数据包进行交互。 它具有多种功能&#xff0c;通过这些功能我们可以轻松伪造和操纵数据包。 通过 scapy 模块&#xff0c;我们可以创建不同的网络工具&#xff0c;如 ARP Spoofer、网络扫描仪、数据包转储器…

swiftUi——颜色

在SwiftUI中&#xff0c;您可以使用Color结构来表示颜色。Color可以直接使用预定义的颜色&#xff0c;例如.red、.blue、.green等&#xff0c;也可以使用自定义的RGB值、十六进制颜色代码或者系统提供的颜色。 1. 预定义颜色 Text("预定义颜色").foregroundColor(.…

Swing程序设计(9)复选框,下拉框

文章目录 前言一、复选框二、下拉框总结 前言 该篇文章简单介绍了Java中Swing组件里的复选框组件、列表框组件、下拉框组件&#xff0c;这些在系统中都是常用的组件。 一、复选框 复选框&#xff08;JCheckBox&#xff09;在Swing组件中的使用也非常广泛&#xff0c;一个方形方…

Albumentations(Augmentation Transformations)

Albumentations&#xff08;Augmentation Transformations&#xff09; Albumentations&#xff08;Augmentation Transformations&#xff09;是一个用于图像数据增强&#xff08;数据增广&#xff09;的Python包。它提供了丰富的图像增强技术&#xff0c;用于训练机器学习模…