C++ struct 笔记(超级详细)
今日碎碎念:我在学C语言时经常用到结构体struct,之后在写C++程序时遇到在struct中定义构造函数和成员函数的情况,这在c语言中是从未遇到过的,觉得奇怪,想到之前并没有真正系统学习C++里的struct,有必要今天详细记录一下。
虽然今天结构体较少使用,但知道它们是什么,以及如何使用它们仍然很重要,这并不仅仅是因为可以在较老的程序中遇到它们,还因为在某些情况(这里请看二、C++ class和struct的区别)下,类的实例无法使用,这时必须使用结构体。
目录
一、C++ struct的用法
1、struct是什么
2、 struct的4种声明定义方式
3、结构体的2种初始化方式
4、结构体成员的访问
5、结构体的嵌套
6、将结构体作为参数和返回值
二、C++ class和struct的区别
三、C++ struct和 c struct的区别
四、struct计算结构体某个成员相对于结构体基址的偏移
一、C++ struct的用法
1、struct是什么
struct是程序员定义的数据类型,将逻辑上连接在一起的不同类型的数据组合到一起的单元。
2、 struct的4种声明定义方式
a. 第一种语法表示
struct 结构体名称
{
数据类型 member1;
数据类型 member2;
};
#include<iostream>
#include <string>
using namespace std;
struct SStudent
{int nNo;std::string strName;
};int main(int argc, char *argv[])
{//使用初始化列表初始化structstruct SStudent s1 = { 1, "ying"}; //C++定义struct变量时,前面的struct可以写SStudent s2 = { 2, "Ming"}; //C++定义struct变量时,前面的struct也可以不写cout << s1.nNo << endl;cout << s1.strName << endl;cout << s2.nNo << endl;cout << s2.strName << endl;return 0;
}
b.第二种语法表示
typedef struct 结构体名称{
数据类型 member1;
数据类型 member2;
}结构体名称别名;
这种情况使用typedef关键字,声明了数据类型的别名,所以在定义结构体 变量时有两种方式:
第一种:结构体名称 构体变量名
第二种:结构体名称别名 结构体变量名
#include<iostream>
#include <string>
using namespace std;typedef struct SStudent
{int nNo;std::string strName;
} SStud;int main(int argc, char *argv[])
{SStudent s1 = { 1, "ying"}; //使用结构体名称SStud s2 = { 2, "Ming"}; //使用结构体名称别名cout << s1.nNo << endl;cout << s1.strName << endl;cout << s2.nNo << endl;cout << s2.strName << endl;return 0;
}
c.第三种语法表示
struct 结构体名称{
数据类型 member1;
数据类型 member2;
}结构体变量;
#include<iostream>
#include <string>
using namespace std;
struct SStudent
{int nNo;std::string strName;
} stu;int main(int argc, char *argv[])
{
// stu s2; //错误,没有使用typedef关键字,stu是变量不是类型stu = { 1, "ying"}; //使用初始化表赋值stu.nNo = 2; //修改成员nNo值stu.strName = "XiaoMing";//修改成员strName值cout << stu.nNo << endl;cout << stu.strName << endl;return 0;
}
d.第四种语法表示
//匿名结构体
struct {
数据类型 member1;
数据类型 member2;
}结构体变量名;
在声明的同时定义了结构体变量,但不能在其它地方声明,因为我们无法得知该结构体的标识符,所以就无法通过标识符来声明变量。
#include<iostream>
#include <string>
using namespace std;//声明了结构体并定义(且只能在这里定义)了两个该结构体的变量,
//由于无法获取结构体名称(因为匿名),所以无法在其他地方定义该结构体变量
struct
{int nNo;std::string strName;
} stu1, stu2;int main(int argc, char *argv[])
{ stu1 = { 1, "ying"}; //使用初始化表赋值stu2 = { 2, "Ming"}; //使用初始化表赋值cout << stu1.nNo << endl;cout << stu1.strName << endl;cout << stu2.nNo << endl;cout << stu2.strName << endl;return 0;
}
3、结构体的2种初始化方式
a. 使用初始化列表
语法:
//初始化列表中的项目是按照结构体声明中成员的顺序依次赋值,各个成员的赋值用逗号分隔并用大括号括起来
结构体类型 变量名 = {member1取值,member2取值,member3取值...};
前面的例子都使用了初始化列表来初始化,这里不再记录例子。
几个注意点:
1)使用初始化列表时可以仅仅初始化部分成员,如果某个成员未被初始化,则所有跟在它后面的成员都需要保留为未初始化。C++未提供跳过某个成员初始化其他成员的方法。
#include<iostream>
#include <string>
using namespace std;//声明了结构体,增加nAge成员,并且定义了两个变量stu1和stu2
struct SStudent
{int nNo;std::string strName;int nAge;
} stu1, stu2;int main(int argc, char *argv[])
{ stu1 = { 1, "ying"}; //合法,仅初始化了nNo和strName,不初始化nAge
// stu2 = { 2, 11}; //非法,不能跳过strName给nAge赋值cout << stu1.nNo << endl;cout << stu1.strName << endl;cout << stu1.nAge << endl;cout << stu2.nNo << endl;cout << stu2.strName << endl;cout << stu2.nAge << endl;return 0;
}
2)可以在结构体声明中使用默认值初始化结构体成员。
#include<iostream>
#include <string>
using namespace std;//声明了结构体,并且定义了两个变量stu1和stu2
struct SStudent
{int nNo = 1;std::string strName = "YunCai";int nAge = 6;
} stu1, stu2;int main(int argc, char *argv[])
{ stu1 = { 2, "ying"}; //不给nAge赋值,将取值默认值6cout << stu1.nNo << endl;cout << stu1.strName << endl;cout << stu1.nAge << endl;cout << stu2.nNo << endl; //不给stu2赋值,所有成员都使用默认值cout << stu2.strName << endl;cout << stu2.nAge << endl;return 0;
}
运行结果:

b. 使用构造函数
与类构造函数一样,结构体的构造函数必须是与结构体名称相同的公共成员函数,并且没有返回类型。因为默认情况下,所有结构体成员都是公开的,所以不需要使用关键字 public。
#include<iostream>
#include <string>
using namespace std;//声明了结构体,
//并且定义了一个带有三个默认参数的构造函数
//在定义SStudent 变量而不向其传递任何参数时,提供默认值
struct SStudent
{int m_nNo;string m_strName;int m_nAge;SStudent(int nNo = 1, string strName = "YunCai", int nAge = 6){m_nNo = nNo;m_strName = strName;m_nAge = nAge;}
};int main(int argc, char *argv[])
{ SStudent stu1; //调用构造函数并且使用默认参数SStudent stu2(2, "ying"); //调用构造函数并传参nNo = 2, strName = "ying"cout << stu1.m_nNo << endl;cout << stu1.m_strName << endl;cout << stu1.m_nAge << endl;cout << stu2.m_nNo << endl;cout << stu2.m_strName << endl;cout << stu2.m_nAge << endl;return 0;
}
4、结构体成员的访问
结构体数据成员都是public的,所以它们可以被直接访问,并且可以像常规变量一样使用。
结构体变量使用点运算符.访问数据成员,结构体指针使用->指针运算符访问数据成员。
#include<iostream>
#include <string>
using namespace std;struct SStudent
{int m_nNo;string m_strName;int m_nAge;SStudent(int nNo = 1, string strName = "YunCai", int nAge = 6){m_nNo = nNo;m_strName = strName;m_nAge = nAge;}
};int main(int argc, char *argv[])
{ SStudent stu1; //调用构造函数并且使用默认参数SStudent stu2(2, "ying"); //调用构造函数并传参nNo = 2, strName = "ying"SStudent* stu3 = new SStudent(3, "Ming", 8); //使用new初始化SStudent对象指针cout << stu1.m_nNo << endl;//使用点运算符访问cout << stu1.m_strName << endl;cout << stu1.m_nAge << endl;cout << stu2.m_nNo << endl;cout << stu2.m_strName << endl;cout << stu2.m_nAge << endl;cout << stu3->m_nNo << endl;//使用指针运算符访问cout << stu3->m_strName << endl;cout << stu3->m_nAge << endl;delete stu3;stu3 = nullptr;return 0;
}
5、结构体的嵌套
就像一个类的对象可以作为成员放在另一个类中,一个结构体的变量可以作为成员放在另一个结构体中。
#include<iostream>
#include <string>
using namespace std;//声明了结构体SDate日期
struct SDate
{int m_nYear;int m_nMonth;int m_nDay;SDate(const int& nY = 2000, const int& nM = 11, const int& nD = 2){m_nYear = nY;m_nMonth = nM;m_nDay = nD;}
};//声明了结构体SStudent学生,其中m_dateBirth是学生出生日期
struct SStudent
{int m_nNo;string m_strName;int m_nAge;SDate m_dateBirth;SStudent(const int& nNo = 1, const string& strName = "YunCai",const int& nAge = 6, const SDate& dateBirth= SDate()){m_nNo = nNo;m_strName = strName;m_nAge = nAge;m_dateBirth = dateBirth;}
};//使用一个函数打印学生信息,参数类型为常量引用SStudent
void print(const SStudent& stu)
{cout << stu.m_nNo << " " << stu.m_strName << " " << stu.m_nAge << " ";cout <<"Birthday:" << stu.m_dateBirth.m_nYear << "_" <<stu.m_dateBirth.m_nMonth << "_" << stu.m_dateBirth.m_nDay << endl;
}//修改学号增加100,参数类型为值传递,返回值为SStudent
SStudent UpdateNo1(SStudent stu)
{stu.m_nNo += 100;return stu;
}//修改学号增加100,参数类型为引用传递
void UpdateNo2(SStudent& stu)
{stu.m_nNo += 100;
}int main(int argc, char *argv[])
{ SStudent stu1; //调用构造函数并且使用默认参数print(stu1);stu1 = UpdateNo1(stu1);print(stu1);SDate stu2_birthday(1999, 9, 10);SStudent stu2(2, "Ying", 7, stu2_birthday);//调用够用构造函数并且传了4个参数print(stu2);UpdateNo2(stu2);print(stu2);return 0;
}
运行结果:
6、将结构体作为参数和返回值
a.将结构体作为参数:与类对象一样,结构体变量也可以通过值、引用和常量引用传递给函数。
1) 值传递:需要生成整个原始结构的副本并传递给函数。因为不希望浪费时间来复制整个结构体,所以,除非结构很小,否则一般会通过引用将结构体传递给函数。
2)引用传递:引用传递不会生成原始结构体的副本,函数可以直接访问原始结构体的成员变量,也可能更改它们。
3)常量引用传递:常量引用传递也不会生成原始结构体的副本,函数直接访问原始结构体的成员变量但不能修改原始结构体的成员变量。
b.将结构体作为返回值:函数的返回类型是结构体的名称。
在5、结构体的嵌套中的例子,print函数使用了常量引用传递进行传值,UpdateNo1函数的参数类型为值传递,返回值为结构体,UpdateNo2函数的参数类型为引用传递。
二、C++ class和struct的区别
结构体和类基本雷同,唯一区别是,类中成员变量默认为私有private,而结构体中则为公有public。因此在使用时,我们可以根据不同的场景或者需求来选择使用struct或者class。
a.这些情况下使用struct比class更好
1)纯数据结构:如果一个类只包含数据成员,而没有成员函数;
2)数据成员全部为public;
3)用于C接口:如果一个类需要与C语言交互,例如作为C语言库的接口,那么使用struct更加合适(因为C语言不支持类的概念,而使用struct可以更加方便地进行数据传递);
4)继承自C结构体:如果一个类需要继承自一个C语言的结构体,那么使用struct更加合适。因为C结构体默认为public,并且在C++中可以使用struct来继承。
b.这些情况下使用class比struct更好
1)需要保证数据的安全性,对数据的访问控制比较严格:使用class可以将数据成员设置为私有成员private,防止外部直接修改数据;
2)需要进行多态:如果一个类需要进行多态操作,例如需要使用虚函数,那么使用class更加合适。
三、C++ struct和 c struct的区别
a. C++中定义结构体变量时可以省略struct,但C语言中不可以省略;
b. C++中struct可以和类一样,有访问权限,并可以定义成员函数; C语言中struct没有访问权限的设置,是一些变量的集合体,不能定义成员函数;
c.C++中struct可以继承,也可以实现多态;C语言中struct不支持继承和多态;
四、struct计算结构体某个成员相对于结构体基址的偏移
如何计算:
#define offsetof(s,m) (size_t)&(((s *)0)->m)
解释:
((s *)0):强制转化成数据结构指针,并使其指向地址0;
((s *)0)->m:使该指针指向成员m
&(((s *)0)->m):获取该成员m的地址
(size_t)&(((s *)0)->m):转化这个地址为合适的类型
使用场景:
offsetof已经被定义在系统库中,所以直接使用offsetof计算结构体某个成员相对于结构体基址的偏移
例子:
要计算如下SDate中m_nDay成员相对于结构体基址的偏移,可以使用 offsetof(SDate, m_nDay)。
struct SDate{
int m_nYear;
int m_nMonth;
int m_nDay;
};
参考资料如下:
1、C++ struct的4种定义方式_c++ struct 定义_Mr顺的博客-CSDN博客
2、C++结构体完全攻略(超详细)
3、什么时候以struct 替代class? - 知乎
相关文章:
C++ struct 笔记(超级详细)
今日碎碎念:我在学C语言时经常用到结构体struct,之后在写C程序时遇到在struct中定义构造函数和成员函数的情况,这在c语言中是从未遇到过的,觉得奇怪,想到之前并没有真正系统学习C里的struct,有必要今天详细…...
Vue基础1:生命周期汇总(vue2)
Description 生命周期图: 可以理解vue生命周期就是指vue实例从创建到销毁的过程,在vue中分为9个阶段:创建前/后,载入前/后,更新前/后,销毁前/后,其他;常用的有:created&…...
Linux串口驱动
《I.MX6ULL 参考手册》第 3561 页的“Chapter 55 Universal Asynchronous Receiver/Transmitter(UART) I.MX6ULL串口原理 1.1UART与USART UART是异步通信,USART是异步/同步通信,比UART多了一条时钟线 USART 的全称是 Universal Synchronous/Asynchr…...
java反编译工具jd-gui使用
文章目录 一、JD-GUI介绍二、下载三、安装四、使用教程五、免责声明摘抄 一、JD-GUI介绍 JD-GUI是一个独立的图形实用程序,显示“.class”文件的Java源代码。 使用JD-GUI浏览重构的源代码,以便即时访问方法和字段。 二、下载 MAC安装包:ht…...
Linux 之 shell 脚本
Linux 之 shell 脚本 1、脚本的格式要求2、shell 脚本常用执行方式2.1、绝对路径或相对路径方式2.2、sh脚本方式(不推荐) 3、shell 的变量3.1、定义 shell 变量3.2、将命令返回值赋值给变量 (重点)3.3、设置环境变量3.4、位置参数…...
如何去阅读开源的第三方库的源码
2023年9月2日,周六晚上 今天探索了一天如何去阅读第三方库的源码,终有所获。 再结合以前看cereal项目的源码的经验,于是就有了这篇博客。 我个人认为: 在阅读一个开源的第三方库之前,要先学会这个第三方库的一些简单…...
浅析Linux虚拟网络技术
文章目录 概述Tap/tun设备tun/tap的工作机制 Bridge网桥Bridge的工作机制Bridge IP 相关参考 概述 在传统的网络环境中,一台物理主机包含一张或多张网卡,要实现与其它物理主机之间的通信,需要将自身的网卡通过路由器或者交换机连接到外部的物…...
设计模式之九:迭代器与组合模式
有许多方法可以把对象堆起来成为一个集合(Collection),比如放入数组、堆栈或散列表中。若用户直接从这些数据结构中取出对象,则需要知道具体是存在什么数据结构中(如栈就用peek,数组[])。迭代器…...
官方推荐:6种Pandas读取Excel的方法
Pandas提供了多种读取Excel文件的方法,以下是官方推荐的6种方法: 1. 使用pd.read_excel()函数 这是最常用的方法,可以读取Excel文件,并将其转换为Pandas数据框。可以指定工作表名和列名的行号。 df pd.read_excel(data.xlsx, …...
Redis与Mysql区别
一、关系型数据库 mysql,pgsql,oracle ,sqlserver 支持连表关联查询(会有一些特定的语法特特性) 二、非关系型数据库 redis,mongodb,memcache (key-value) 三、关系型数据库与非关系型数据库的区别: 1&am…...
Black-Box Tuning for Language-Model-as-a-Service
本文是LLM系列的文章,针对《Black-Box Tuning for Language-Model-as-a-Service》的翻译。 语义模型即服务的黑盒调整 摘要1 引言2 背景3 方法4 实验5 讨论与未来工作 摘要 GPT-3等超大的预训练语言模型(PTM)通常作为服务发布。它允许用户设…...
通用的ARM64架构镜像
#此链接包含x86架构和ARM架构的pytorch镜像,镜像里面已下载好各种第三方库,GPU版本的pytorch可用。缺点:镜像有点大 测试环境:操作系统麒麟银河V10,ARM64处理器(cpu),显卡为T4显卡 …...
git大文件推送报错
报错信息 不多掰扯,直接上报错信息和截图 Delta compression using up to 8 threadsRPC failde; HTTP 413 curl 22 The requested URL returned error: 413 Request Entity Too Large从以上的报错信息不难看出推送仓库的时候,请求体过大,为…...
RDMA性能优化经验浅谈
一、RDMA概述 首先我们介绍一下RDMA的一些核心概念,当然了,我并不打算写他的API以及调用方式,我们更多关注这些基础概念背后的硬件执行方式和原理,对于这些原理的理解是能够写出高性能RDMA程序的关键。 Memory Region RDMA的网…...
day 44 | ● 309.最佳买卖股票时机含冷冻期 ● 714.买卖股票的最佳时机含手续费
309.最佳买卖股票时机含冷冻期 此外,在返回的时候,由于状态234都是卖出的状态,所以要比较其最大值进行返回。 func maxProfit(prices []int) int {dp : make([][]int, len(prices))dp[0] make([]int, 4)dp[0][0] -prices[0]for i : 1; i &…...
电子科大软件系统架构设计——系统分析与设计概述(含课堂作业、练习答案)
系统分析与设计概述 信息系统概述 what 信息系统是一种能够完成对业务数据进行采集、转换、加工、计算、分析、传输、维护等信息处理,并能就某个方面问题给用户提供信息服务的计算机应用系统。 组成 信息化基础设施(计算机、计算机网络、服务器、系统…...
【SpringMVC】@RequestMapping注解(详解)
文章目录 前言1、RequestMapping注解的功能2、RequestMapping注解的位置3、RequestMapping注解的value属性4、RequestMapping注解的method属性1、对于处理指定请求方式的控制器方法,SpringMVC中提供了RequestMapping的派生注解2、常用的请求方式有get,po…...
8.(Python数模)马尔科夫链预测
Python实现马尔科夫链预测 马尔科夫链原理 马尔科夫链是一种进行预测的方法,常用于系统未来时刻情况只和现在有关,而与过去无关。 用下面这个例子来讲述马尔科夫链。 如何预测下一时刻计算机发生故障的概率? 当前状态只存在0(故…...
什么是浏览器缓存(browser caching)?如何使用HTTP头来控制缓存?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 浏览器缓存和HTTP头控制缓存⭐ HTTP头控制缓存1. Cache-Control2. Expires3. Last-Modified 和 If-Modified-Since4. ETag 和 If-None-Match ⭐ 缓存策略⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击…...
谁需要了解学习RPA?什么地方可以使用RPA?
RPA(Robotic Process Automation)是一种通过软件机器人自动化执行特定任务和流程的技术。以下是一些需要了解RPA的人群: 企业决策者:企业决策者需要了解RPA的潜在收益和风险,以及如何将其纳入企业的数字化转型战略中。…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案
一、延迟敏感行业面临的DDoS攻击新挑战 2025年,金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征: AI驱动的自适应攻击:攻击流量模拟真实用户行为,差异率低至0.5%,传统规则引…...
