首页 > 编程语言 >[C++] 结构体 struct 详解

[C++] 结构体 struct 详解

时间:2024-11-27 15:30:02浏览次数:9  
标签:num struct int C++ 详解 Student 对齐 结构

目录

前言

演示用编译器及其标准

Dev C++ 6.7.5 Red panda  C++14

先   赞   后   看    养   成   习   惯  

正文

1、结构体(struct)是什么

概念

struct 与 calss 的区别

应用场景:

2、定义、声明与初始化

三种定义结构体的方法:

结构体变量初始化

1.默认构造函数

2.自定义构造函数

3、结构体嵌套 

4、结构体数组

结构体数组的定义:

定义不定长度的结构体数组:

方法一:

 方法二:

获取结构体数组长度: 

5、结构体指针

6、结构体指针成员

指向文字常量区:

指向堆区: 

7、结构体的拷贝

浅拷贝

深拷贝

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

9、结构体的对齐规则

为什么要对齐

强制对齐规则

有趣的问答

10、共用体 union

简单应用:

11、枚举 enum

简单应用:

后记


前言

今天zty带来的是结构体(struct)的详解,搞了4个小时,大家给个赞呗,zty还要上学,发作品会少一点

                                                  先   赞   后   看    养   成   习   惯

zty郑桐羽呀

                                                  先   赞   后   看    养   成   习   惯  

演示用编译器及其标准

Dev C++ 6.7.5 Red panda  C++14

先   赞   后   看    养   成   习   惯  

正文

1、结构体(struct)是什么

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

2、定义、声明与初始化

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

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

struct Struct{
	int Code;
	string Name;
};
Struct zty;

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

struct Struct{
	int Code;
	string Name;
} zty;

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

struct{
	int Code;
	string Name;
} zty;
结构体变量初始化
1.默认构造函数
struct Struct{
	int Code;
	string Name;
};
Struct zty = {50, "tom"};
2.自定义构造函数
struct Struct{
	int Code;
	string Name;
    Struct (int code, string name){
		Code = code;
		Name = name;
    }
};
Strctt zty = {50, "tom"};

3、结构体嵌套 

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

#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;
}

4、结构体数组

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

结构体数组的定义:

C++结构体数组的定义和定义结构体变量的方法相仿,只需声明其为数组即可

struct Student{ 
    int num;//学号 
    char sex;//性别 
    int age;//年龄 
  };
  Student stu[3] = {
	{ 1001,'M', 21 },
	{ 1002,'W', 23 },
	{ 1003,'W', 25 },
};
struct Student{ 
    int num;//学号 
    char sex;//性别 
    int age;//年龄 
 };
 int main(){
    Student stu[3]= {
		{ 1001,'M', 21 },
		{ 1002,'W', 23 },
		{ 1003,'W', 25 },
	};
 }
定义不定长度的结构体数组:
方法一

定义一个结构体数组,为该数组开辟一块大的存储空间,然后进行初始化赋值。

#include <iostream>
using namespace std;

struct Student{
	int num;//学号 
	char sex;//性别 
	int age;//年龄 
};

int main() {
	int sum = 0;
	cout << "请输入学生总数:" << endl;
	cin >> sum;
	struct Student *stu;
	stu = (struct Student *)malloc(sum * sizeof(struct Student));
	for (int i = 0; i < sum; i++)
	{
		int _num, _age;
		char _sex;
		cout << "请输入第" << (i + 1) << "位学生的信息(学号 性别 年龄):" << endl;
		cin >> _num >> _sex >> _age;
		stu[i].num = _num;
		stu[i].sex = _sex;
		stu[i].age = _age;
	}

	for (int i = 0; i < sum; i++)
	{

		cout << "第" << (i + 1) << "位学生:" << endl;
		cout << stu[i].num << "  " << stu[i].sex << "  " << stu[i].age << endl;
	}
	system("PAUSE");
	return 0;
}

 方法二

通过vector来进行动态数组的赋值操作 

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Student{
	int num;//学号 
	char sex;//性别 
	int age;//年龄 
};

int main() {
	int sum = 0;
	cout << "请输入学生总数:" << endl;
	cin >> sum;
	vector<Student> stu;
	Student tmp;

	for (int i = 0; i < sum; i++)
	{
		int _num, _age;
		char _sex;
		cout << "请输入第" << (i + 1) << "位学生的信息(学号 性别 年龄):" << endl;
		cin >> _num >> _sex >> _age;
		tmp.num = _num;
		tmp.sex = _sex;
		tmp.age = _age;
		stu.push_back(tmp);
	}

	for (int i = 0; i < sum; i++)
	{

		cout << "第" << (i + 1) << "位学生:" << endl;
		cout << stu[i].num << "  " << stu[i].sex << "  " << stu[i].age << endl;
	}
	system("PAUSE");
	return 0;
}

获取结构体数组长度: 
	int len = sizeof(stu) / sizeof(struct Student );

5、结构体指针

  • 结构体指针变量本质是变量,只是该变量保存的是结构体变量的地址。
  • 在使用结构体指针时,要使用箭头运算符(->)来访问成员变量。因为指针本身只存储了地址信息,而不是结构体本身,所以需要使用箭头运算符来指示指针所指向的结构体中的成员变量。
    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;
    }
    

6、结构体指针成员

指向文字常量区:
struct Stu{
	int num;
	char *name;
};
struct Stu lucy={101,"hello world"};

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

7、结构体的拷贝

浅拷贝
  • 相同类型的结构体变量可以整体赋值,默认方式是浅拷贝
  • 如果结构体中没有指针成员,浅拷贝不会带来任何问题。如果结构体中有指针成员,浅拷贝会带来多次释放堆区空间的问题。
    #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;
    }
    
    深拷贝
  • 深拷贝是指复制一个新的对象,其中包含原始对象中所有成员变量的副本,而不是只简单地复制指向成员变量数据的指针。
  • 如果结构体中有指针成员,尽量使用深拷贝。

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

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

#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;
}

9、结构体的对齐规则

为什么要对齐

假设有这样一个结构体:

struct Data{
	char a;
	int b;
};

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

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

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

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

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

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

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

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

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

10、共用体 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;

11、枚举 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";
    }
}

后记

作者:zty郑桐羽呀

联系方式:(不挂了,有事私信)

兄弟们给个赞呗

    先   赞   后   看    养   成   习   惯

标签:num,struct,int,C++,详解,Student,对齐,结构
From: https://blog.csdn.net/zty20120913/article/details/143987984

相关文章

  • 华为OD机试E卷 --最大报酬 --24年OD统一考试(Java & JS & Python & C & C++)
    文章目录题目描述输入描述输出描述用例题目解析JS算法源码Java算法源码python算法源码c算法源码c++算法源码题目描述小明每周上班都会拿到自己的工作清单,工作清单内包含n项工作,每项工作都有对应的耗时时间(单位h)和报酬,工作的总报酬为所有已完成工......
  • 华为OD机试E卷 --绘图机器人--24年OD统一考试(Java & JS & Python & C & C++)
    文章目录题目描述输入描述输出描述用例题目解析js算法源码Java算法源码python算法源码c算法源码c++算法源码题目描述绘图机器的绘图笔初始位置在原点(0,0)机器启动后按照以下规则来进行绘制直线.尝试沿着横线坐标正向绘制直线直到给定的终点E期间......
  • AI在人力资源-员工关系中的应用详解
    AI在人力资源-员工关系中的应用详解目录员工与企业关系劳动合同智能管理工作环境优化建议员工之间的关系社交网络分析提升团队合作员工互动情绪监控劳动关系管理劳动争议预测与调解建议员工申诉自动分类与分析代码示例与解读示例:自动化意见收集与分类员工与企业......
  • AI在人力资源-组织发展中的应用详解
    AI在人力资源-组织发展中的应用详解目录战略制定AI驱动的市场和竞争分析组织战略模拟与预测结构改进组织网络分析(ONA)优化结构基于AI的职位职责重新设计流程优化业务流程自动化与效率分析流程瓶颈检测与优化建议代码示例与解读示例:组织网络分析(ONA)战略制定AI驱......
  • C/C++ openCV实现实时课室管理系统
    该系统能实时展示教室的使用状态,它通过分析摄像头传回的视频信息来判断教室中是否有课程正在进行,并将这些信息即时更新到教学楼大厅的显示屏上。由于各种不可预见的原因,预先制定的课程表可能无法准确反映教室的实际使用情况,因此这个实时系统提供了更加准确的参考。核心功能:(1)......
  • C++ 类和对象(初始化列表)
    目录一、前言二、正文1.初始化列表1.1初始化的格式1.2初始化列表的使用1.2.1引用成员变量初始化1.2.2const成员变量1.2.3没有默认构造函数的成员变量必须在初始化列表初始化2.成员变量声明处给缺省值一、前言前面我们已经用所学知识运算符重载写了一个日期计算器......
  • jmeter测试udp接口详解
    jmeter测试udp广播(jmeter发送udp)jmeter测试udp广播(jmeter接收udp)先下载安装第三方插件下载链接:https://jmeter-plugins.org/install/Install/ 将下载的插件放在lib/ext目录里面 然后重启jmeter,如下图操作:          此时可以看到lib/ext目录里面多了......
  • 详解AI数字人直播的封号风险-青否数字人抖音稳定直播带货!
    AI数字人直播面临封号风险,这一风险主要来自对直播平台各项规定的遵循情况。不同的直播平台有不同的管理政策,如果AI数字人直播的内容违反了这些规定,就有可能导致账号被封禁。除此之外,以下几种风险也是AI数字人直播需要重点规避的。1.直播内容违规如果直播内容包含违法、违......
  • 【leetcode】括号生成 c++回溯法
    22.括号生成 22.括号生成-力扣(LeetCode)数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。示例1:输入:n=3输出:["((()))","(()())","(())()","()(())","()()()"]示例2:输入:n=1输出:["()"]提示:1<=n<=8......
  • C++ 多继承基类析构虚函数
    Demo:classAnimal{public:Animal(){cout<<"animal..."<<endl;}virtual~Animal(){cout<<"~animal..."<<endl;}virtualvoidShowAnimal()=0;};classCa......