C语言学习之结构体
在C语言中,我们已经学了好几种类型的数据。比如整型int、char、short等,浮点型double、float等。但是这些都是基本数据类型,而这些数据类型应用在实际编程里显然是不够用的。比如我们没有办法用一旦数据类型来定义一个”人“的属性。因此这里我们需要一个框,将不同的数据类型放在一起,这就是结构体,接下来我们将深入学习结构体的知识。
结构体
结构体的创建与初始化
结构体是一些值的集合,这些值被称之为成员变量。结构的每个成员都是不同类型的变量。
语法结构:
struct name//名字自定义
{member-list;//一个或者多个成员变量
}variable-list//可以省略。是结构体变量列表
举例说明
struct person
{char name[20];int age;float height;
};
int main()
{struct person p1 = {"诗华",18,1.72};return 0;
}
结构体的特殊声明
声明结构体的时候可以不完全声明。
但是匿名结构体的声明其后必须创建变量
struct//匿名结构体类型
{char name[20];int age;float height;
}s1,s2;
匿名结构体类型只能用一次。
但是切记这种方法不行
拓展:数据结构简单科普
链表是一种数据结构。数据结构是描述数据在内存当中的存储结构,对数据的操作就是对数据结构的操作。
大体上数据结构分为以下几种
结构的自引用
在结构体中包含一个类型为该结构本身的成员是否可以呢?
上图报错的原因:结构体内不能包含同类型的自己。
如果想正确表达,需要这样
struct Node
{int data;struct Node *next;
};int main()
{printf("%zd\n",sizeof(struct Node));/*struct person p1 = {"诗华",18,1.72};*/return 0;
}
结果为:
而在上图中,int data为数据域,struct Node * next为指针域。
也可以简化为:
typedef struct Node
{int data;struct Node *next;
}Node;
之后如果使用结构体定义变量可以直接写为
Node n;
但是这么些是绝对错误的
typedef struct
{int data;Node *next;
}Node;
结构体内存对齐
我们学会结构体的基本使用后,那么问题来了,结构体的大小是怎么计算的呢?我们举例分析。
#include<stdio.h>
struct s1
{char c1;//1char c2;//1int n;//4
};
struct s2
{char c1;//1int n;//4char c2;//1
};
struct s3
{double d1;//8int n;//1char c1;//4
};
struct s4
{double d1;//8struct s3 S;//16char c2;//1
};
int main()
{printf("%zd\n",sizeof(struct s1));printf("%zd\n", sizeof(struct s2));printf("%zd\n",sizeof(struct s3));printf("%zd\n",sizeof(struct s4));return 0;
}
结果为:
为什么是这样呢?
结构体成员在存储的时候有内存对齐的现象。
这里介绍一个新概念:offsetof——一个宏,可以计算出一个结构体成员相较于结构体起始位置的偏移量。(其实之前博主的博客预处理那节讲解过:C语言学习之预处理指令-CSDN博客)
内存对齐的规则
1.结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处。
2.其他成员变量要对齐到某个数字(对齐数)的整数被的地址处
对齐数=编译器默认的一个对齐数与该成员变量大小的较小值。
VS中默认的值为8
Linux中gcc编译器没有默认对齐数,对齐数就是成员变量自身的大小
3.结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数,所有对齐数中最大值)的整数倍
4.如果嵌套了结构体的情况下,嵌套的结构体成员对齐到自己成员中最大对其数的整数倍,结构体的整体大小就是所有最大对其数(含嵌套结构体中成员的对齐数)的整数倍。
为什么会存在内存对齐?
1.不是所有的硬件平台都能访问任意地址的任意数据;某些硬件平台只能在某些地址处去某些特定类型的数据。
2.数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要做两次内存访问;而对齐的内存访问仅仅需要一次访问。
总结来说:结构体的内存对齐是拿空间换取时间的做法
那在设计结构体的时候,我们既要满足对齐,又要节省空间如何做到呢“
让占用空间小的成员尽量集中在一起。
struct A
{char c1;char c2;int n;
};
struct B
{char c1;int n;char c2;
};
int main()
{printf("%zd\n",sizeof(struct A));printf("%zd\n",sizeof(struct B));return 0;
}
修改默认对齐数
#pragma这个预处理指令可以改变编译器默认对齐数量。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#pragma pack(1)//设置结构体默认对齐数为1
struct S
{char c1;int n;char c2;
};
#pragma pack()//恢复默认对齐数int main()
{printf("%d\n",sizeof(struct S));return 0;
}
结构体传参
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{int data[1000];int num;
};
struct S s = { {1,2,3,4,5} ,1000 };
//结构体传参
void print1(struct S s)
{printf("%d\n",s.num);
}
void print2(struct S *ps)
{printf("%p\n",ps->num);
}
int main()
{print1(s );print2(&s);return 0;
}
上面的print1和print 2哪个更好呢?答案是print2
原因:
函数传参的时候,参数是需要压栈的,会有时间和空间上系统的开销。
如果传递一个结构体对象时,结构体体积过大,参数压栈的系统开销过大,会导致性能下降。
结论:结构体传参的时候,要穿结构体的地址
结构体实现位段
位段
位段的声明和结构必须要类似,有两个不同。
1.位段的成员必须是int,unsigned int或者signed int 。在C99中位段成员类型也可以是其他类型
2.位段的成员名之后有一个冒号和一个数字
#include<stdio.h>
//结构体
struct A
{int a;int b;int c;int d;
};
//位段
struct B
{int _a:2;int _b : 3;int _c : 10;int _d : 5;
};
int main()
{printf("%zd\n", sizeof(struct A));printf("%zd\n", sizeof(struct B));return 0;
}
结构体和位段的大小分别为:
位段的空间是如何开辟的呢?
位段的内存分配
1.位段的成员可以是:int,unsigned int或者signed int或者char类型
2.位段的空间上按照需要以4个字节和1个字节的方式开辟
3.位段涉及很多不确定因素,位段是不跨平台的,注重可移植程序的程序避免使用。
//位段
struct B
{int _a:2;int _b : 3;int _c : 10;int _d : 30;
};
int main()
{/*printf("%zd\n", sizeof(struct A));*/printf("%zd\n", sizeof(struct B));return 0;
}
1.int位段被当成有符号还是无符号不确定
2.位段最大位的数目不确定(16位机器最大16,32位机器最大32.写成27的话16 位机器会出问题)
3.位段成员在内存中从左向右分配还是右向左分配是不确定的
4.当一个结构体包含两个位段的时候,第二个位段成员比较大,无法荣达第一个剩余的位时是舍弃剩余位置还是保留不确定
总结:与结构相比,位段可以达到同样的效果,更加节省空间不过会有跨平台的问题。
位段的应用
在网络协议的IP数据报中,用位段可以更节省空间的达到想要的效果,对网络畅通很有帮助。
位段使用的注意事项
位段的几个成员共同用一个字节,这样有i协成员起始位置并不是某个字节起始位置,那么这些位置只是没有地址的。内存中每个字节分配一个地址,一个字节内部的比特位是没有地址的。
所以不能对位段的成员使用&*操作符,这样就不能直接使用scanf直接给位段的成员输入值。只能先输入放在一个变量里然后赋值给位段的成员
struct B
{int _a:2;int _b : 5;int _c : 10;int _d : 30;
};
int main()
{struct B s = {0};scanf("%d",&sa.b);//这是错误的//正确示范int b = 0;scanf("%d",b);sa._b = b;return 0;
}
感谢看到这里的读者朋友,求一个赞谢谢。
相关文章:
C语言学习之结构体
在C语言中,我们已经学了好几种类型的数据。比如整型int、char、short等,浮点型double、float等。但是这些都是基本数据类型,而这些数据类型应用在实际编程里显然是不够用的。比如我们没有办法用一旦数据类型来定义一个”人“的属性。因此这里…...
layui获取无法获取表单数据,data.field一直为空
form.on(submit(*), function(data){console.log(data.field) //当前容器的全部表单字段,名值对形式:{name: value}return false; //阻止表单跳转。如果需要表单跳转,去掉这段即可。}); console.log(data.field)一直显示为空࿰…...
「Mac畅玩AIGC与多模态02」部署篇01 - 在 Mac 上部署 Ollama + Open WebUI
一、概述 本篇介绍如何在 macOS 环境下本地部署 Ollama 推理服务,并通过 Open WebUI 实现可视化交互界面。该流程无需 CUDA 或专用驱动,适用于 M 系列或 Intel 芯片的 Mac,便于快速测试本地大语言模型能力。 二、部署流程 1. 环境准备 安装 Homebrew(如尚未安装):/bin…...
量子力学:量子通信
量子通信是利用量子力学原理对信息进行编码、传输和处理的新型通信方式,以下是其详细介绍及业界发展现状: 基本原理 量子叠加态 :量子系统可以处于多个状态的叠加,如光子的偏振方向可以同时处于水平和垂直方向的叠加态ÿ…...
《大型网站技术架构-核心原理与案例分析》笔记
:::info 💡 根据 遗忘曲线:如果没有记录和回顾,6天后便会忘记75%的内容 读书笔记正是帮助你记录和回顾的工具,不必拘泥于形式,其核心是:记录、翻看、思考::: 书名大型网站技术架构-核心原理与案例分析作者…...
log4cpp进阶指南
📝 log4cpp进阶指南 1. 按天切割日志 log4cpp 默认是按文件大小来切割日志的。为了按天切割日志,通常需要自己进行时间判断并手动处理日志文件的切割。 1.1 解决方案 虽然 RollingFileAppender 只支持按大小切割,但你可以使用以下策略&…...
树莓派超全系列教程文档--(43)树莓派内核简介及更新
树莓派内核简介及更新 简介更新 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 简介 Raspberry Pi 内核是 托管在 GitHub 上;更新滞后于上游 Linux内核。上游内核持续更新,而 Raspberry Pi 则将 Linux 内核的长期版本整合…...
第二章、在Windows上部署Dify:从修仙小说到赛博飞升的硬核指南
第1章:安装 wsl (Windows Subsystem for Linux) 上一章我们聊了什么是Dify,这一章我们讲一下怎么才能用Dify。 使用Dify就需要我们在本地部署Dify; 部署Dify就需要用到”Docker“; 要想使用“Docter”就需要用到wsl。 那什么是wsl呢?简单来说就是让你的电脑拥有另一个叫…...
淘宝商品主图标题api接口
1、输入淘宝商品id或者链接,点查询 2、查询淘宝商品主图,商品标题,商品价格,卖家旺旺 3、支持api接口...
小结:BFD
*BFD(双向转发检测,Bidirectional Forwarding Detection)是一种快速、轻量级的故障检测机制,用于检测网络中两点之间的连通性。它广泛应用于各种场景 1. 检测 IP 链路 应用场景: BFD 用于检测两台设备之间的 IP 层连…...
收藏按钮变色问题
1.问题描述 无论是否收藏,收藏按钮都显示黄色,但点击收藏按钮后却能发生颜色变化 2.解决思路 经过调试发现isCollected返回的是整个对象,因此在store的方法里面找到了相应的函数进行修改使得isCollected返回相应的值 修改前: 修…...
小程序发布后,不能强更的情况下,怎么通知到用户需要去更新?
哈喽,我想和大家分享一下我在开发记账小程序时遇到的一个问题,以及我找到的解决办法。 这个记账小程序从一开始,我就特别在意用户的隐私,所以把记账数据都存到了本地缓存里,还做了个手动备份的功能。但系统嘛…...
4.2.2 MySQL索引原理以及SQL优化
文章目录 4.2.2 MySQL索引原理以及SQL优化1. 索引与约束1. 索引是什么2. 索引的目的3. 几种索引4. 约束1.外键2. 约束 vs 索引的区别 5. 索引实现1. 索引存储2. 页3. B树4. B树层高问题5. 自增id6. 聚集索引7. 辅助索引 8. innnodb体系结构1. buffer pool2. change buffer 9. 最…...
02_值相同、类型不同,用 equals() 比较为什么是 false?
02_值相同、类型不同,用 equals() 比较为什么是 false? 场景示例 Map<Long, String> map; Integer keyWord 4; if (map.containsKey(keyWord)) {// ... }结果: → 编译通过,但 containsKey 返回 false,逻辑错…...
leetcode--盛最多水的容器,接雨水
11.盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明:你不…...
AlexNet网络搭建
AlexNet网络模型搭建 环境准备 首先在某个盘符下创建一个文件夹,就叫AlexNet吧,用来存放源代码。 然后新建一个python文件,就叫plot.py吧,往里面写入以下代码,用于下载数据集: # FashionMNIST里面包含了…...
常用第三方库:sqflite数据库应用
常用第三方库:sqflite数据库应用 一、基础概念 1.1 什么是sqflite? sqflite是Flutter官方推荐的SQLite数据库插件,它提供了在Flutter应用中使用SQLite数据库的能力。SQLite是一个轻量级的、嵌入式的关系型数据库,特别适合移动应…...
【论文阅读】-周总结-第5周
1. 【论文阅读24】并行 TCN-LSTM 风电预测模型(2024-02) 链接 论文信息: Liu S, Xu T, Du X, et al. A hybrid deep learning model based on parallel architecture TCN-LSTM with Savitzky-Golay filter for wind power prediction. Ener…...
深入理解 JavaScript 的 typeof 运算符:返回的数据类型
JavaScript 的 typeof 运算符是开发中用于检测值类型的基础工具。虽然看似简单,但其行为存在需要开发者理解的微妙细节。本文将解析 typeof 返回的数据类型,探讨边界案例,并分享类型检查的最佳实践。 typeof 会返回哪些类型? typ…...
前端零基础入门到上班:【Day8】JavaScript 基础语法入门
前端零基础入门到上班:【Day8】JavaScript 基础语法入门(超全!!!) 一、JavaScript 简介二、引入 JavaScript 的三种方式三、变量与常量(var、let、const)3.1 var (传统方式ÿ…...
ppt流程图怎么?ppt流程图模板大全
ppt流程图怎么?ppt流程图剪头模板,ppt流程图模板大全: ppt流程图_模板素材_PPT模板_ppt素材_免抠图片_AiPPTer...
makefile总结
Makefile 学习视频:1、野火的基础入门篇-第32讲 Makefile三要素_哔哩哔哩_bilibili 2、b站视频04 一个稍复杂的Makefile_哔哩哔哩_bilibili 学习资料:第2个视频对应的Make/make.md 无限十三年/CPP - 码云 - 开源中国 ch0_Makefile简介 Makefile是什…...
MIME 类型是个什么东西?
MIME 类型(Multipurpose Internet Mail Extensions)即多用途互联网邮件扩展类型,它是一种标准,用于表示文档、文件或字节流的性质和格式。 最初设计用于电子邮件系统,后来被广泛应用于网页、HTTP 协议等领域࿰…...
javaWeb开发---前后端开发全景图解(基础梳理 + 技术体系)
在现代互联网开发中,前端与后端的分工协作非常重要。本文结合实际架构图,全面梳理前端技术栈、后端技术栈以及服务器端整体流程,帮助初学者建立清晰的整体认知。 一、整体架构概览 系统整体划分为三个主要部分: B端(…...
spring-rabbit的CachingConnectionFactory默认参数导致消费者Channel数量暴增问题解决
文章目录 1.前言2.解决2.1消费监听方法中关闭channel2.2 配置设置两个参数 3.总结 1.前言 由于之前写了一个好用的rabbitmq-spring-boot-start启动器,后面在生产实践之后反馈消费者连接的Channel数量过多,一个消费者的Channel数量可以达到好几百…...
线上JVM调优与全栈性能优化 - Java架构师面试实战
线上JVM调优与全栈性能优化 - Java架构师面试实战 本文通过一场互联网大厂的Java架构师面试,深入探讨了线上JVM调优、OOM定位、死锁定位、内存和CPU调优、线程池调优、数据库调优、缓存调优、网络调优、微服务调优及分布式调优等关键领域。 第一轮提问 面试官&am…...
【KWDB创作者计划】_企业级多模数据库实战:用KWDB实现时序+关系数据毫秒级融合(附代码、性能优化与架构图)
一、技术背景与行业痛点 1.1 多模数据融合挑战 场景痛点: 工业物联网设备每秒产生百万级传感器数据(时序数据)。需关联设备档案(关系数据)生成设备健康报告,传统方案需多数据库跳转,延迟>5…...
“八股训练营”学习总结
在参加为期 40 天的八股训练营的这段时间里,我收获满满,不仅在知识技能上得到了提升,更在学习习惯和自我认知方面有了很大的进步。 在知识层面,训练营涵盖了网络、数据库、缓存以及python测试开发等多方面的知识点。 网络方面&a…...
java工具类
LocalDateTime LocalDateTime可以获取当前时间: LocalDateTime now LocalDateTime.now(); 同时他也可以获取指定时间: LocalDateTime dateTime LocalDateTime.of(2023, 5, 15, 10, 30) 若我们时间值超出了我们的实际情况值,我们将会出现…...
「OC」源码学习——alloc与init的实现
「OC」源码学习——alloc与init的实现 前言 费劲千辛万苦终于项目给写完了,进入下一个阶段,源码的学习 alloc的调用顺序 我们在main函数之中打上断点,先运行 再在alloc之中的各个函数之中打上断点,在关键步骤上打上断点&#…...
AOSP Android14 Launcher3——动画核心类QuickstepTransitionManager详解
Launcher3中,有一个类在跟桌面相关的各种动画中扮演着非常关键的角色,这个类就是QuickstepTransitionManager。 QuickstepTransitionManager在aosp中的路径为:aosp/packages/apps/Launcher3/quickstep/src/com/android/launcher3/QuickstepT…...
STM32:看门狗
独立看门狗 简介 独立看门狗(IWDG)由独立的低速时钟(LSI)驱动,即便主时钟发生故障,它依然能够正常工作。其主要作用是在程序出现异常时,通过复位来保障系统的稳定性。独立看门狗的喂狗操作相对…...
第十三步:vue
Vue 1、上手 1、安装 使用命令:npm create vuelatestvue文件后缀为.vueconst app createApp(App):初始化根组件app.mount("#app"):挂载根组件到页面 2、文件 script标签:编写jstemplate标签:编写htmls…...
《代码整洁之道》第8章 边界 - 笔记
甚至是你团队里其他组写的你无法随意修改的代码。 这些外部代码是你的**“边界”。它们可能会升级、可能会有 Bug、可能会有反人类的设计、甚至你将来可能想换一个类似的库或服务。如果你的应用代码直接且紧密地依赖**这些外部代码的具体类、方法、异常等细节,那么…...
【CF】Day45——Codeforces Round 1021 (Div. 2) BC
阅读理解。。。不过挺有意思( B. Sasha and the Apartment Purchase 题目: 思路: 看了半天没看懂... 题目叽里咕噜一大堆,说白了就是让我们在一个 可删除k个数 的 数组 中选 一些点 且 这些点的f(x) 是此时 删完了k个数之后的数组…...
《代码整洁之道》第5章 格式 - 笔记
你应该选择一套管理代码格式的简单规则。如果是团队,应该选择一套团队一致同意采用的简单格式规则。 最重要的原则:一致性(Consistency)! 没有完美的格式规范,但有统一的规范。 整个团队(或者…...
通过示例学习:连续 XOR
通过示例学习:连续 XOR 如果我们想在 PyTorch 中构建神经网络,可以使用 (with) 指定所有参数(权重矩阵、偏差向量),让 PyTorch 计算梯度,然后调整参数。但是,如果我们有很…...
加密算法 AES、RSA、MD5、SM2 的对比分析与案例(AI)
加密算法 AES、RSA、MD5、SM2 的对比分析 一、相同点 密码学基础 均为现代密码学核心算法,用于保障数据安全。数据处理 均涉及数据转换(加密、签名、哈希等)。密钥依赖 AES、RSA、SM2 依赖密钥(对称或非对称&#x…...
基于STM32、HAL库的MAX31865模数转换器ADC驱动程序设计
一、简介: MAX31865是一款高精度的铂电阻温度检测器(RTD)至数字转换器,具有以下特点: 支持2线、3线或4线RTD配置 15位ADC分辨率 可编程RTD和基准电阻 内置故障检测(开路、短路等) SPI接口通信 工作电压:3.0V至3.6V 二、硬件接口: STM32L4XX <--> MAX31865 PA5(SCK…...
Laravel5.7的一些用法
1、事件需要运行 php artisan queue:work 2、数据库对象关联 1对1 hasOne 1对多 hasMany 1依赖多 belongsTo 多依赖多 belongsToMany 3、 关联查询 with 关联统计 withCount 统计时指定字段名。 如: withCount([cardHolderOrders as order_count]); 4、 // 一次查询&…...
Vue3 + OpenLayers 开发教程 (六)WebGL渲染优化
1. WebGL 渲染优化 1.1 WebGL 渲染器配置 创建 src/utils/webgl.ts: import { Map } from ol; import { WebGLPointsLayer } from ol/layer; import { Vector as VectorSource } from ol/source; import { Style, Circle, Fill, Stroke } from ol/style;// 创建 …...
【C++】C++11新特性(一)
文章目录 列表初始化initializer_list左值引用和右值引用 列表初始化 在 C98 中可以使用{}对数组或者结构体元素进行统一的列表初始值设定 struct Point {int _x;int _y; }; int main() {int array1[] { 1, 2, 3, 4, 5 };int array2[5] { 0 };Point p { 1, 2 };return 0; …...
【网络原理】 网络编程套接字
文章目录 一、网络编程基础1. 为什么需要网络编程?2. 什么是网络编程3 .网络编程中的基本概念发送端和接收端请求和响应客户端和服务端 4. 常见的客户端服务端模型 二、Socket套接字1. 概念2.分类3. Java数据报套接字通信模型4.Java流套接字通信模型 三、UDP数据报套…...
每天五分钟深度学习框架pytorch:使用visdom绘制损失函数图像
visdom的安装 pip install visdom如果安装失败 pip install --upgrade visdom开启visdom python -m visdom.server nohup python -m visdom.server后台启动然后就会出现,下面的页面,我们可以使用下面的链接打开visdom页面 Visdom中有两个重要概念: env环境。不同环境的可…...
【MySQL专栏】MySQL数据库表的内外连接
文章目录 1、表的内连接(1)内连接的语法格式①显示SMITH的名字和部门名称 2、外连接(1)左外连接左外连接的语法格式通过实例演示: (2)右外连接右外连接的语法格式通过实例演示 1、表的内连接 什…...
-信息革命-
信息革命-马歇尔麦克卢汉(MARSHALL McLUHAN),1964年 随着大系统的加速崩溃,作为塑造经济生活和收入分配的一个因素,系统性的强 制将会式微。很快,在社会机构的组织中,效率将会比权力的分配更加重…...
Charles 抓包入门教程
一、什么是 Charles? Charles 是一款功能强大的抓包工具,可以拦截、查看、分析电脑和手机上的 HTTP/HTTPS 网络请求。常用于: 查看网页或App发送的请求和返回的数据调试接口、分析问题模拟网络环境(断网、慢速网络)修…...
深度学习新趋势:利用MLP取代卷积层——S2-MLPv2模型解析
深度学习新趋势:利用MLP取代卷积层——S2-MLPv2模型解析 近年来,深度学习领域不断涌现出新的技术革新,而其中最引人注目的趋势之一就是用多层感知机(MLP)替代传统的卷积层。这种转变不仅带来了计算效率的提升…...
【玩转 JS 函数式编程_016】DIY 实战:巧用延续传递风格(CPS)重构倒计时特效逻辑
文章目录 巧用延续传递风格(CPS)重构倒计时特效逻辑1 起因2 换一种思路3 填坑之旅4 复盘与小结 写在前面 都说念念不忘,必有回响。写过的文章也好,看过的视频也罢,其实只要用心积累,不必刻意去死记硬背&…...
虚函数表的设计和多态的实现
虚表指针 类直接定义虚函数:编译器自动在对象头部插入 vptr。 继承含虚函数的父类:子类复用父类的 vptr,不会创建新的vptr 单继承(子类继承一个含虚函数的父类) 1.创建新的虚函数表 2.沿用父类的虚表指针ÿ…...