C 语言结构体
本博客涉及的结构体知识有:
1.0:结构体的创建和使用
2.0: typedef 关键字与#define 关键字的区别
3.0: 结构体成员的访问【地址访问与成员访问】
4.0: 结构体嵌套调用
5.0 数组访问赋值结构体成员
......
1.0:结构体的创建和使用
结构体类型和枚举类型一样,是一种用户自定义的数据类型,它可以使用一个变量来描述事物的多种属性,便于数据的管理,数据类型声明的语法格式:或者说->【结构是一些值的集合,这些值被称为成员变量,结构体中的成员可以是不同的变量类型 】,和数组相比结构体的数据类型更为的灵活,数组指的是一组相同类型的值的集合,数组的下标是从0开始的。
格式1:
// 结构体的声明格式
typedef struct
{成员列表
}structName_t;注:成员列表中的成员并不是变量在什么的时候并不会开辟内存空间内存空间的开辟要在创建结构体变量之后************************************ 结构体: 创建结构体案例* 参数 : 结构体成员 char name[20]; char tel[12];* 返回值: 无* 时间 : 2024/7/13 * 作者 : _沧浪之水_************************************
**/
typedef struct
{char name[20];char tel[12];char sex[5];int high;
}People_t;
格式2:
结构体变量的声明struct Person
{
// 成员列表char name[20];int age;
}struct_name_t;上面的结构体是一个结构体数据类型,并不是一个变量,创建结构体类型的时候并不会开辟内存空间struct Stu
{
// 成员列表char name[20];int age;
}s1,s2;
s1 与 s2 是 struct Stu 类型的变量(s1 s2 是结构体成员的全局变量)
格式3:
// 结构体成员变量声明
struct Point
{int x;int y;}p1 = {2,3};struct score
{int n;char ch;};struct Stu
{char name[20];int age;struct score s;};成员变量的初始化
int main()
{struct Stu s1 = {"8888",20,{100,'q'}};printf(%s %d %d %c,s1.name,s1.age,s1.n,s1.s.ch);}
结构体变量的定义
/************************************** 结构体: 结构体变量定义后同时进行赋值* 参数 : 无参数* 返回值: 无返回值* 时间 : 2024/7/13 * 作者 : _沧浪之水_************************************
**/
People_t peo = { "张三","15863310892","男",181 };
2.0 typedef 关键字的使用
typedef关键关键字:用于定义一个已有关键字的别名,具体创建格式如下所示
/************************************** 结构体: typedef 关键字的用法* 参数 : 无参数* 返回值: 无返回值* 时间 : 2024/7/13 * 作者 : _沧浪之水_************************************
**/
typedef 数据类 名字typedef uint8_t uint;typedef unsigned char uchar;
typedef 关键字和define关键字的区别,两者都是给对象取一个别名增强程序的可读性【尽量防止程序中魔鬼数字的出现】,两者有如下的区别
1: 使用场景不同
- typedef 关键字用于给数据类型定义别名
- #define关键字又称为(宏定义) 用于给数字,表达式(写表达式时注意带上括号防止异常问题的出现),代码语句定义别名。
2:执行时机不同
- typedef在编译阶段执行;
- #define在预编译阶段执行;
3:定义方法不同
- #define别名在替换对象的前面,并且定义后面不用加分号;
#define PI 3.14#define MAX_NUM_LIST 9
typedef的别名在替换对象的后面,并且定义后面需要加分号;
typedef unsigned char uchar;
3.0: 结构体成员的访问
注:有指针访问和圆点运算符访问两种访问方式
使用圆点运算符并打印输出
/************************************** 结构体: 结构体成员变量访问* 参数 : 结构体成员访问* 返回值: 无* 时间 : 2024/7/13 * 作者 : _沧浪之水_**************************************/// peo 是结构体变量,结构体变量创建后才会开辟内存控制,结构体变量初始化People_t peo = { "张三","15863310892","男",181 };// 浮点数在内存中不能精确的存储,结构体嵌套初始化recallStruct_t recal = { {"李四","15863310892","男",181},100, 88.8f };printf("%s %s %s %d\n", peo.name, peo.tel, peo.sex, peo.high);printf("%s %s %s %d %d %f\n", recal.p.name,recal.p.tel,recal.p.sex, recal.p.high,recal.num,recal.f);
使用指针访问【地址访问】
/************************************** 结构体: 结构体传递地址调用* 参数 : *p 指针地址* 返回值: 无* 时间 : 2024/7/13 * 作者 : _沧浪之水_************************************
**/
void Print(People_t *p)
{// 左边的是结构体指针 “结构体指针->成员变量”printf("%s %s %s %d\n", p->name, p->tel, p->sex, p->high);
}
注:以上的这种写法需要在主函数中进行调用
4.0: 结构体嵌套调用
#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>/************************************** 结构体: 创建结构体* 参数 : 结构体成员 char name[20]; char tel[12];* 返回值: 无* 时间 : 2024/7/13* 作者 : _沧浪之水_************************************
**/
typedef struct
{char name[20];char tel[12];char sex[5];int high;
}People_t;/************************************** 结构体: 创建结构体* 参数 : 结构体成员,内部包含结构体【顺带变量初始化,结构体初始化】* 返回值: 无* 时间 : 2024/7/13* 作者 : _沧浪之水_************************************
**/
typedef struct
{People_t p;int num;float f;
}recallStruct_t;/************************************** 结构体: 结构体传递地址调用* 参数 : *p 指针地址* 返回值: 无* 时间 : 2024/7/13* 作者 : _沧浪之水_************************************
**/
void Print(People_t *p)
{// 左边的是结构体指针 “结构体指针->成员变量”printf("%s %s %s %d\n", p->name, p->tel, p->sex, p->high);
}/************************************** 结构体: 结构体成员变量访问* 参数 : 结构体成员访问* 返回值: 无* 时间 : 2024/7/13* 作者 : _沧浪之水_************************************
**/
void PrintTwo(People_t input)
{// 左边的是结构体变量 “结构体变量.成员变量”printf("%s %s %s %d\n", input.name, input.tel, input.sex, input.high);
}int main()
{// peo 是结构体变量,结构体变量创建后才会开辟内存控制,结构体变量初始化People_t peo = { "张三","15863310892","男",181 };// 浮点数在内存中不能精确的存储,结构体嵌套初始化recallStruct_t recal = { {"李四","15863310892","男",181},100, 88.8f };printf("%s %s %s %d\n", peo.name, peo.tel, peo.sex, peo.high);printf("%s %s %s %d %d %f\n", recal.p.name, recal.p.tel, recal.p.sex, recal.p.high, recal.num, recal.f);Print(&peo);PrintTwo(peo);return 0;
}
注:以上的注释编写方式仅限于更好的理解知识,实际的开发过程会更为规范,推荐书籍《高质量 C C++ 编程指南 》。
注:上面的两种打印输出方式哪一种打印方式更好,结构体传递参数吧 “对象” 进行结构体传参的时PrintTwo() 这种参数传递方式方式时PrintTwo(peo),peo实际是一个对象已经在内存中开辟了一块内存空间,如果把对象作为实际参数传递给形参的时候“形参里面的内容实际上是实际参数的一份拷贝” 打印peo的时候打印输出的数据是一样的,空间和时间的浪费会降低程序的性能。【推荐使用地址传递的方式把参数的地址传递进去(地址的大小就是4-8字节)通过地址找到数据】参数传递的时候会压栈,结构体传递参数的时候尽量传递结构体的地址节省时间和空间。
5.0 数组方式给结构体成员赋值
#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>#define MAX_LIST_NUM (sizeof(arrList) / sizeof(arrList[0]))/************************************** 结构体: 创建结构体* 参数 : 结构体成员 char name[20]; char tel[12];* 返回值: 无* 时间 : 2024/7/13* 作者 : _沧浪之水_************************************
**/
typedef struct
{char name[20];char tel[12];char sex[5];int high;
}People_t;static People_t arrList[] =
{{"Keil","122345625","男",180},{"Ling","122345625","女",185}
};int main()
{uint8_t i = 0;for (i = 0; i < MAX_LIST_NUM; i++) {printf("%s %s %s %d\n", arrList[i].name, arrList[i].tel, arrList[i].sex, arrList[i].high);}return 0;
}
6.0 结构体内存对齐
现代处理器在读取或写入内存时,倾向于处理特定长度的数据,这些长度通常是2字节、4字节、8字节等。这是因为处理器内部的总线宽度、缓存行大小和寄存器大小通常是这些值的倍数。当数据对齐到这些边界时,处理器可以更高效地读取或写入数据,避免了多次内存访问或者额外的数据重排操作,从而提高了执行速度。
-
硬件限制
某些硬件平台不能在任意内存地址上访问任意数据类型。例如,一些处理器可能无法直接读取非对齐的长字节数据,尝试这样做可能会导致硬件异常,比如对齐错误(alignment fault)。
-
跨平台和移植性
不同的硬件架构可能有不同的内存对齐偏好。如果一个结构体在一个架构下没有正确对齐,而在另一个架构下被读取,可能会导致不可预测的行为或错误。通过遵循标准的对齐规则,可以增强代码的跨平台兼容性和可移植性。
-
内存访问模式
对齐也有助于优化缓存行为。缓存通常以特定大小的块存储数据,如果数据对齐得当,就更有可能在缓存命中时加载更多的相关数据,从而减少缓存缺失和提高性能。
结构体内存定义示意图:
offsetof结构体偏移量验证
#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>struct s1
{char a; int i;char b;
};struct s2
{char b;char a;int i;
};int main()
{struct s1 sOne;struct s2 sTwo;printf("%d\n", sizeof(struct s1));printf("%d\n", sizeof(struct s2));printf("|+----------+|----------+|---------+|-----------|");// 使用offsetof计算偏移量printf("%d\n", offsetof(struct s1,a));printf("%d\n", offsetof(struct s1,i));printf("%d\n", offsetof(struct s1,b));return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>struct s1
{char a; int i;char b;
};struct s2
{char b;char a;int i;
};int main()
{struct s1 sOne;struct s2 sTwo;printf("%d\n", sizeof(struct s1));printf("%d\n", sizeof(struct s2));printf("|+----------+|----------+|---------+|-----------|");printf("\n");// 使用offsetof计算偏移量printf("%d\n", offsetof(struct s1,a));printf("%d\n", offsetof(struct s1,i));printf("%d\n", offsetof(struct s1,b));printf("%d\n", offsetof(struct s2, b));printf("%d\n", offsetof(struct s2, a));printf("%d\n", offsetof(struct s2, i));return 0;
}
计算结构体成员的大小
嵌套结构体大小计算
结构体修改默认对齐数
#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>// 修改默认对齐数
#pragma pack(4)
struct S
{int i; // 4 ----- > 4 和 4 进行比较那就是 4 double d; // 8 -----> 8 和 4 进行比较那么还是 4
};
#pragma pack()int main()
{printf("%d\n", sizeof(struct S)); // 12return 0;
}
结构体参数传递方式
注:结构体传递参数的方式一共有两种,一个是地址传递,一个是.操作符传递,函数传递参数的时候,需要压栈,会有时间和空间上的系统开销如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大会导致程序性能的下降,涉及结构体参数传递的时候尽量使用地址传递的方式。
结构体传递参数方式 1
#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>struct S
{int data[100];int num;
};static void Print(struct S ss)
{uint8_t i;for (i = 0; i < 3; i++) {printf("%d ", ss.data[i]);}printf("%d ", ss.num);
}int main()
{struct S s = { {1,6,8},100 };Print(s);return 0;
}
结构体传递参数方式 2
#define _CRT_SECURE_NO_WARNINGS
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include <string.h>
#include "add.h"
#include <stdint.h>struct S
{int data[100];int num;
};static void Print(struct S ss)
{uint8_t i;for (i = 0; i < 3; i++) {printf("%d ", ss.data[i]);}printf("%d ", ss.num);
}static void Print_p(struct S *ps)
{uint8_t i;for (i = 0; i < 3; i++){printf("%d ", ps->data[i]);}printf("%d ", ps->num);
}
int main()
{struct S s = { {1,6,8},100 };Print(s);printf("\n");printf("|-------------+----------+------+------|\n");Print_p(&s);return 0;
}
......
相关文章:

C 语言结构体
本博客涉及的结构体知识有: 1.0:结构体的创建和使用 2.0: typedef 关键字与#define 关键字的区别 3.0: 结构体成员的访问【地址访问与成员访问】 4.0: 结构体嵌套调用 5.0 数组访问赋值结构体成员 ...... 1.0:结构体的创建和使用 结…...

MySQl高级篇-主从复制
主从复制 复制的基本原理 slave会从master读取binlog来进行数据同步 MySQL复制过程分成三步: master将改变记录到二进制日志(binary log)。这些记录过程叫做二进制日志事件,binary log events;slave将master的binary log events拷贝到它的中继日志(r…...

JMeter案例分享:通过数据验证的错误,说说CSV数据文件设置中的线程共享模式
前言 用过JMeter参数化的小伙伴,想必对CSV Data Set Config非常熟悉。大家平时更关注变量名称,是否忽略首行等参数,其余的一般都使用默认值。然而我最近遇到一个未按照我的预想读取数据的案例,原因就出在最后一个参数“线程共享模…...

数学建模·Topsis优劣解距离法
Topsis优劣解 一种新的评价方法,特点就是利用原有数据,客观性强。 相较于模糊评价和层次评价 更加客观,充分利用原有数据,精确反映方案差距 基本原理 离最优解最近,离最劣解越远 具体步骤 正向化 代码与原理与熵权…...

数学建模中常用的数据处理方法
常用的数据处理方法 本文参考 B站西电数模协会的讲解视频 ,只作笔记提纲,想要详细学习具体内容请观看 up 的学习视频。国赛的 C 题一般数据量比较大。 这里介绍以下两种方法: 数据预处理方法 数据分析方法 数据预处理方法 1. 数据清洗 为…...

C嘎嘎:函数模版和类模版
目录 泛型编程 函数模版 函数模版概念 函数模版的格式 函数模版的原理 函数模版的实例化 函数参数的匹配原则 类模版 类模版的定义格式 类模版的实例化 泛型编程 如何实现一个通用的交换函数呢 void Swap(int& left, int& right) {int temp left;left rig…...

使用 Apache Pulsar 构建弹性可扩展的事件驱动应用
本视频来自 2024 Apache Pulsar 欧洲峰会,由 David Kjerrumgaard, 《Pulsar in Action》书作者给大家带来的《使用 Apache Pulsar 构建弹性可扩展的事件驱动应用》分享。 嘉宾|David Kjerrumgaard,Apache Pulsar Committer,《Pul…...
【国产开源可视化引擎Meta2d.js】视频
视频 meta2d 支持Html音视频。 // 音频 const pen {name: video,x: 100,y: 100,width: 100,height: 10,audio: https://down.ear0.com:3321/preview?soundid37418&typemp3,autoPlay: true, }; meta2d.addPen(pen); meta2d.inactive();// 视频 const pen {name: video,x…...

零信任网络安全
随着数字化转型的发生,网络边界也在不断被重新定义,因此,组织必须使用新的安全方法重新定义其防御策略。 零信任是一种基于“永不信任,永远验证”原则的安全方法,它强调无论在公司内部或外部,任何用户、设…...

Python酷库之旅-第三方库Pandas(022)
目录 一、用法精讲 55、pandas.lreshape函数 55-1、语法 55-2、参数 55-3、功能 55-4、返回值 55-5、说明 55-6、用法 55-6-1、数据准备 55-6-2、代码示例 55-6-3、结果输出 56、pandas.wide_to_long函数 56-1、语法 56-2、参数 56-3、功能 56-4、返回值 56-5…...

数据建设实践之大数据平台(一)准备环境
大数据组件版本信息 zookeeper-3.5.7hadoop-3.3.5mysql-5.7.28apache-hive-3.1.3spark-3.3.1dataxapache-dolphinscheduler-3.1.9大数据技术架构 大数据组件部署规划 node101node102node103node104node105datax datax datax ZK ZK ZK RM RM NM...
VUE2用elementUI实现父组件中校验子组件中的表单
需求是VUE2框架用elementUI写复杂表单组件,比如,3个相同功能的表单共用一个提交按钮,把相同功能的表单写成一个子组件,另一个父组件包含子组件的重复调用和一个提交按钮,并且要求提交时校验必填项。 注意: …...

人工智能算法工程师(中级)课程9-PyTorch神经网络之全连接神经网络实战与代码详解
大家好,我是微学AI,今天给大家介绍一下人工智能算法工程师(中级)课程9-PyTorch神经网络之全连接神经网络实战与代码详解。本文将给大家展示全连接神经网络与代码详解,包括全连接模型的设计、数学原理介绍,并从手写数字识别到猫狗识…...

UDP网络通信(发送端+接收端)实例 —— Python
简介 在网络通信编程中,用的最多的就是UDP和TCP通信了,原理这里就不分析了,网上介绍也很多,这里简单列举一下各自的优缺点和使用场景 通信方式优点缺点适用场景UDP及时性好,快速视网络情况,存在丢包 与嵌入…...
从零开始实现大语言模型(五):缩放点积注意力机制
1. 前言 缩放点积注意力机制(scaled dot-product attention)是OpenAI的GPT系列大语言模型所使用的多头注意力机制(multi-head attention)的核心,其目标与前文所述简单自注意力机制完全相同,即输入向量序列 x 1 , x 2 , ⋯ , x n x_1, x_2, \cdots, x_n x...
PTA 7-15 希尔排序
本题目要求读入N个整数,采用希尔排序法进行排序,采用增量序列{5,3,1},输出完成增量5和增量3后的5子排序和3子排序结果。 输入格式: 输入不超过100的正整数N和N个整数(空格分隔)。 输出格式: …...
【密码学】分组密码的设计原则
分组密码设计的目标是在密钥控制下,从一个巨大的置换集合中高效地选取一个置换,用于加密给定的明文块。 一、混淆原则 混淆原则是密码学中一个至关重要的概念,由克劳德香农提出。混淆原则就是将密文、明文、密钥三者之间的统计关系和代数关系…...

深入解析【C++ list 容器】:高效数据管理的秘密武器
目录 1. list 的介绍及使用 1.1 list 的介绍 知识点: 小李的理解: 1.2 list 的使用 1.2.1 list 的构造 知识点: 小李的理解: 代码示例: 1.2.2 list 迭代器的使用 知识点: 小李的理解࿱…...

NFS服务器、autofs自动挂载综合实验
综合实验 现有主机 node01 和 node02,完成如下需求: 1、在 node01 主机上提供 DNS 和 WEB 服务 2、dns 服务提供本实验所有主机名解析 3、web服务提供 www.rhce.com 虚拟主机 4、该虚拟主机的documentroot目录在 /nfs/rhce 目录 5、该目录由 node02 主机…...

自动驾驶事故频发,安全痛点在哪里?
大数据产业创新服务媒体 ——聚焦数据 改变商业 近日,武汉城市留言板上出现了多条关于萝卜快跑的投诉,多名市民反映萝卜快跑出现无故停在马路中间、高架上占最左道低速行驶、转弯卡着不动等情况,导致早晚高峰时段出现拥堵。萝卜快跑是百度 A…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...