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

news2025/1/12 0:53:21

文章目录

    • 一、 结构体(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的结构体指针变量,并将其指向s
    student *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;
else
    cin>>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.coloradmin.cn/o/1294957.html

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

相关文章

老有所依:TSINGSEE青犀养老院智能视频监管方案

养老院智能监控方案是为了提高养老院内老人的安全和护理质量&#xff0c;利用智能技术与监控设备进行全方位的监控和管理&#xff0c;可以加强对老人的监护和护理&#xff0c;提高养老院的服务质量和安全性。 旭帆科技基于视频技术与AI智能分析技术构建的养老院智能视频监控方…

算法:常见的链表算法

文章目录 链表算法两数相加两两交换链表中的节点重排链表合并K个升序链表K个一组翻转链表 总结 本篇总结常见的链表算法题和看他人题解所得到的一些收获 链表算法 关于链表的算法&#xff1a; 画图&#xff1a;画图可以解决绝大部分的数据结构的问题&#xff0c;任何的算法题…

Ubuntu 安装 CUDA 和 cuDNN 详细步骤

我的Linux系统背景&#xff1a; 系统和驱动都已安装。 系统是centos 8。查看自己操作系统的版本信息&#xff1a;cat /etc/issue或者是 cat /etc/lsb-release 用nvidia-smi可以看到显卡驱动和可支持的最高cuda版本&#xff0c;我的是12.2。驱动版本是535.129.03 首先&#…

snakeyaml编辑yaml文件并覆盖注释

文章目录 前言技术积累实战演示1、引入maven依赖2、覆盖注释工具类3、snakeyaml工具类4、测试用例5、测试效果展示 写在最后 前言 最近在做一个动态整合框架的项目&#xff0c;需要根据需求动态组装各个功能模块。其中就涉及到了在application.yaml中加入其他模块的配置&#…

Kubernetes(K8s 1.27.x) 快速上手+实践,无废话纯享版

文章目录 1 基础知识1.1 K8s 有用么&#xff1f;1.2 K8s 是什么&#xff1f;1.3 k8s 部署方式1.4 k8s 环境解析 2 环境部署2.1 基础环境配置2.2 容器环境操作2.3 cri环境操作2.4 harbor仓库操作2.5 k8s集群初始化2.6 k8s环境收尾操作 3 应用部署3.1 应用管理解读3.2 应用部署实…

浏览器提示不安全

当我们使用浏览器访问一个网站时&#xff0c;如果该网站使用的是HTTPS连接&#xff0c;那么浏览器会对其进行安全性的检查。其中一项重要的检查就是确认该网站是否拥有有效的SSL证书。然而&#xff0c;有时我们会在浏览器中看到“不安全”的警告&#xff0c;这通常是由于SSL证书…

【Go自学版】02-goroutine

利用时间片分割进程&#xff0c;致使宏观上A,B,C同时执行&#xff08;并发&#xff09; CPU利用率包含了执行和切换&#xff0c;进程/线程的数量越多&#xff0c;切换成本也会增大 最大并行数&#xff1a;GOMAXPROCS work stealing: 偷其他队列的G hand off: 当前G1阻塞&#…

中缀表达式转后缀表达式与后缀表达式计算(详解)

**中缀表达式转后缀表达式的一般步骤如下&#xff1a; 1&#xff1a;创建一个空的栈和一个空的输出列表。 2&#xff1a;从左到右扫描中缀表达式的每个字符。 3&#xff1a;如果当前字符是操作数&#xff0c;则直接将其加入到输出列表中。 4&#xff1a;如果当前字符是运算符&a…

禅道v11.6 基于linux环境下的docker容器搭建的靶场

一、环境搭建 linux环境下的 在docker环境下安装禅道CMS V11.6 docker run --name zentao_v11.6 -p 8084:80 -v /u01/zentao/www:/app/zentaopms -v /u01/zentao/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD123456 -d docker.io/yunwisdom/zentao:v11.6二、常见问题 1.删除…

软件开发的代码审查工具

在进行软件开发时&#xff0c;代码审查&#xff08;Code Review&#xff09;是一种非常重要的实践&#xff0c;它有助于发现潜在的问题、提高代码质量&#xff0c;并促使团队成员之间的知识共享。有许多工具可用于简化和优化代码审查过程。以下是一些常见的代码审查工具&#x…

力扣541.反转字符串 II

文章目录 力扣541.反转字符串 II示例代码实现总结收获 力扣541.反转字符串 II 示例 代码实现 class Solution {public String reverseStr(String s, int k) {char[] ans s.toCharArray();for(int i0;i<ans.length;i2*k){int begin i;int end Math.min(ans.length-1,begin…

【EI会议征稿】2024年粤港澳大湾区数字经济与人工智能国际学术会议(DEAI2024)

2024年粤港澳大湾区数字经济与人工智能国际学术会议(DEAI2024) 2024 Guangdong-Hong Kong-Macao Greater Bay Area International Conference on Digital Economy and Artificial Intelligence(DEAI2024) 2024年粤港澳大湾区数字经济与人工智能国际学术会议(DEAI2024)由广东科…

Emacs之dired模式重新绑定键值v(一百三十一)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

搞懂HashTable, HashMap, ConcurrentHashMap 的区别,看着一篇就足够了!!!

&#x1f6e9;️&#x1f6e9;️&#x1f6e9;️ 今天给大家分享的是 HashTable, HashMap, ConcurrentHashMap之间的区别&#xff0c;也是自己学习过程中的总结。 清风的CSDN博客 &#x1f6e9;️&#x1f6e9;️&#x1f6e9;️希望我的文章能对你有所帮助&#xff0c;有不足的…

为什么每个 Java 开发者都需要了解 Scala

前面我们一起回顾了第九期 Scala & Java Meetup 中最受关注的话题 —— jdk 并发编程的终极解决方案&#xff1a;虚拟线程&#xff0c;探讨了这一新特性对包括 Scala 在内的响应式编程语言的影响。 本次 Meetup 的首位分享者 Chunsen&#xff0c;在加入 Tubi 成为 Scala 开…

Linux 进程优先级

什么是进程的优先级 优先级&#xff1a;对资源的访问顺序&#xff01;注意优先级与权限的区别&#xff0c;优先级决定的是访问资源的顺序&#xff0c;这意味着无论是谁都可以访问到资源&#xff1b;但是如果你没有权限&#xff0c;你是不能访问资源的&#xff01; 这个应该比较…

XXL-JOB日志相关报错的原因

1.问题&#xff1a;msg&#xff1a;job handler [myJobHandler] not found. 原因&#xff1a;执行器中没有对应的执行器。 执行器中代码展示&#xff1a; Component Slf4j public class JobHandler {XxlJob(value "abcHandler")public void abcHandler() {log.inf…

卷积神经网络中用1*1 卷积有什么作用或者好处呢?

一、来源&#xff1a;[1312.4400] Network In Network &#xff08;如果11卷积核接在普通的卷积层后面&#xff0c;配合激活函数&#xff0c;即可实现network in network的结构&#xff09; 二、应用&#xff1a;GoogleNet中的Inception、ResNet中的残差模块 三、作用&#x…

【C++】:STL源码剖析之vector类容器的底层模拟实现

&#x1f4da;1.vector接口总览 namespace lyp {//模拟实现vectortemplate<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;//默认成员函数vector(); //构造函数vector(size_t n, const …