电子商务平台是什么意思/快速将网站seo
结构体
- 结构体的声明与使用
- 结构体的声明与初始化
- 结构体的自引用
- 结构体的内存对齐
- 对齐规则
- 为什么存在内存对齐
- 修改默认对齐数
- 结构体的传参
- 结构体实现位段
- 什么是位段
- 位段的内存分配
- 位段的跨平台问题
- 位段使用的注意事项
结构体:是一个自定义的类型,成员可以有一个或者多个,类型可以不同。
结构体的声明与使用
结构体的声明与初始化
struct 结构体名
{成员变量;....
};
//结构体初始化
struct Stu
{char name[20];int age;char sex[10];
};
int main()
{struct Stu s1={"lisi",18,"man"};return 0;
}
结构体还存在一中特殊声明:匿名结构体
struct
{成员变量;...
};
这个结构体在声明时不需要写入结构体名,但是在使用时,只能使用一次
比如下面这段代码:
struct
{int a;int b;float c;
}x;
struct
{int a;int b;float c;
}*p;
int main()
{p=&x;return 0;
}
这段代码在编译时会报警告,因为编译器会把这两个声明当成两个不同的类型。
结构体变量的声明与初始化:
直接上代码:
//在声明结构体的同时声明结构体变量并初始化
struct stu
{int a;int b;float c;
}x={1,2,1.0};
int main()
{return 0;
}
///
struct stu
{int a;int b;float c;
};
int main()
{struct stu x={1,2,1.0};//声明结构体变量并初始化return 0;
}
对结构体数组成员初始化。
struct Stu
{char name[20];int age;char sex[10];
};
int main()
{struct Stu s1={"lisi",18,"man"};printf("%s %d %s",s1.name,s1.age,s1.sex);//输出结构体的值return 0;
}
结构体的自引用
若结构体中包含一个结构体本身的成员(自引用),是否可以?
比如定义一个链表节点:
struct Node
{int data;struct Node next;
};
思考一下,这段代码正确吗?
答案当然是“错误”的。因为以这样的方式嵌套定义结构体,那么这结构体的大小将是无穷大的。
正确的自引用应该是下面这样的:
struct Node
{int data;struct Node*next;
};
这在后面将会学到,这其实是建立了一个链表的节点,定义一个结构体指针,让结构体指针指向结构体的数据域(data),再让被指向的结构体的指针成员(next)指向下一个结构体的数据域(data)。
typedef关键字
typedef关键字使用来对类型进行重命名的。
比如:
typedef int i;
将int 重命名为i
typedef char c;
将char重命名为c。
或许你会有这么一个想法“int、char一个就3个字母,一个就4个字母,我为什么还有重命名?重命名它俩还要多打一个typedef,不是更麻烦吗?”
确实,在这中情况下,确实没必要对数据类型重命名,但是在c语言中除了基本数据类型,还有自定义的数据类型。就如我们这篇文章的所讲的结构体类型
,当我们定义了一个结构体类型后,要声明一个结构体变量就需要将struct 结构体名
都打出来,但是如果我们使用typedef关键字对它重命名,就能方便很多了。
typedef struct Student
{int age;char name[20];
}S;
int mian()
{S s1={18,"lisi"};return 0;
}
但是要注意一点,重命名的类型需要重命名完后才能使用,否则编译器过不了编译,比如:
typedef struct Student
{int age;S *next;
}S;
这里,提前使用了结构体struct Student类型重命名后的名字S,是不可以的,因为编译器是从上往下编译代码的,当编译到S*next时,S还没有被编译到,所以对于编译器来说,S类型是不存在的。正确的形式应该像下面这样子。
typedef struct Student
{int age;char name[20];
}S;
int main()
{S s1={18,"lisi"};return 0;
}
结构体的内存对齐
到这里,我们已经掌握了结构体的基本使用,那么我们再接着思考“定义的结构体的大小是多少?int是4字节,char是1字节,那么结构体呢?”
在讨论结构体大小之前,我们先了解一下结构体的对齐规则
对齐规则
结构体对齐规则:是指结构体中每个成员变量的存放地址要满足一定的条件,以提高内存的访问效率。
结构体对齐规则:
- 结构体的第一个成员对齐到结构体变量起始位置偏移量为0的地址处
- 结构体其余成员对齐到对齐数的整数倍的地址处
- 对齐数=编译器默认的对齐数与该成员变量自身大小两者之间的较小值,vs中默认对齐数为8,Linux中gcc没有默认对齐数
- 结构体总大小为最大对齐(所以成员变量都有一个对齐数,选最大的那一个)的整数倍
- 如果结构体2嵌套了一个结构体1则这个嵌套的结构体1的对齐数=自身成员变量的最大对齐数,结构体2的大小就是最大对齐数的整数倍
比如:
struct Stu
{int age;char a;int b;
}S;
则这个结构体的大小为计算过程:
在思考的过程中,你应该已经发现了:内存对齐存在内存浪费
。是的,内存对齐就是一种用空间换时间的做法。
为什么存在内存对齐
硬件平台限制:并不是所有硬件都能够任意读取任意地址处的数据的,某些硬件只能访问某些特定地址下的数据,如果不进行内存对齐,则cpu将不会读取到特定地址处的数据。
性能问题:cpu在读取内存时,是按照一个固定的粒度来读取的(比如一次四字节、8字节),如果结构体不按照一定的规则进行内存对齐,那么cpu在读取一份数据的时候,可能需要读取两次、三次甚至更多次才能把一份数据读完,而进行内存对齐后,cpu则只需要读取一次就行了。
修改默认对齐数
#pragma
,这个预处理指令可以修改默认对齐数 。
#pragma(1);//将默认对齐数修改为1
struct Stu
{int age;char [name];
}s;
int main()
{printf("%zd",sizeof(struct Stu));//输出12//若把#pragma(1)注释掉,默认对齐数恢复到8,次数输出6return 0;
}
当结构体的对齐数不合适的时候,我们就可以通过#pragma来修改默认对齐数。
结构体的传参
struct S
{int age;char name[20];float i;
};struct S s = {18,"lisi",1.0};void print1(struct S s)
{printf("%d %s %lf\n",s.age,s.name,s.i);
}void print2(struct S *s)
{printf("%d %s %lf\n",s->age,s->name,s->i);
}int main()
{print1(s);print2(&s);return 0;
}
结构体传参也分为两类:
- 传值调用
- 传址调用
在传参时,推荐使用传址调用,因为函数传参的时候,参数是需要压栈的,会有时间与空间上的系统开销。
传值调用,如果传入的参数过大,这个开销也就会变大。
但如果传入地址,地址大小就两种情况:4字节/8字节,所有推荐使用传址调用。
结构体实现位段
什么是位段
什么是位段:是一种数据结构,它允许将数据以位(bit)的形式紧凑地存储,并允许程序员对此结构的位进行操作
位段的声明与结构体类似:
struct A{int _a:2;int _b:5;int _c:10;int _d:30;};
这段代码中,struct A
占8个字节:
int占4个字节,所以第一次开辟空间大小为4字节,4字节=32bit,但是struct A里,四个成员共占47bit,所以4字节的空间无法存储struct A类型的数据,,需要在开辟一个Int类型的空间,所以该位段大小为8字节。
位段的内存分配
位段的成员可以是Int家族,或者char等
位段空间的分配按照需要以4个字节或者1个字节的方式来开辟的
位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使⽤位段
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
给定空间后,空间内存按照从左到右还是从右到左使用呢?这个不确定,标准没有定义
当剩下的空间不足以分配位段成员时,是浪费这部分空间还是继续使用?没有定义
我们假设空间是从右往左使用,空间是被浪费的
此时最后一个字节就完全倍浪费掉了。
位段的跨平台问题
- int 位段被当成有符号数还是⽆符号数是不确定的。
- 位段中最⼤位的数⽬不能确定。(16位机器最⼤16,32位机器最⼤32,写成27,在16位机器会
出问题。 - 位段中的成员在内存中从左向右分配,还是从右向左分配,标准尚未定义。
- 当⼀个结构包含两个位段,第⼆个位段成员⽐较⼤,⽆法容纳于第⼀个位段剩余的位时,是舍弃
剩余的位还是利⽤,这是不确定的。
总结:
跟结构相⽐,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在
位段使用的注意事项
位段的有些成员的起始位置并不是字节的起始位置,就好比上图中的‘a’,‘b’,我们知道,每个字节都有自己的地址,1字节=8bit,这8bit是没有地址的,所以在使用位段时,我们不能对位段成员使用&(取地址)操作符,也不能进行scanf操作,如果需要给位段成员赋值,需要先给一个变量赋值,在通过这个变量赋值给位段成员
相关文章:

【c语言】自定义类型-结构体
结构体 结构体的声明与使用结构体的声明与初始化结构体的自引用 结构体的内存对齐对齐规则为什么存在内存对齐修改默认对齐数 结构体的传参结构体实现位段什么是位段位段的内存分配位段的跨平台问题位段使用的注意事项 结构体:是一个自定义的类型,成员可…...

2-链表-71-环形链表 II-LeetCode142
2-链表-71-环形链表 II-LeetCode142 参考:代码随想录 LeetCode: 题目序号142 更多内容欢迎关注我(持续更新中,欢迎Star✨) Github:CodeZeng1998/Java-Developer-Work-Note 技术公众号:CodeZeng1998&#…...

【UnityShader入门精要学习笔记】第十七章 表面着色器
本系列为作者学习UnityShader入门精要而作的笔记,内容将包括: 书本中句子照抄 个人批注项目源码一堆新手会犯的错误潜在的太监断更,有始无终 我的GitHub仓库 总之适用于同样开始学习Shader的同学们进行有取舍的参考。 文章目录 表面着色器…...

Python社会经济 | 怀特的异方差一致估计量
🎯要点 🎯算法和模型底层数学及代码:🖊线性代数应用(主成分分析):降维、投影(用于求解线性系统)和二次形式(用于优化)| 🖊奇值分解…...

《被讨厌的勇气》笔记
自由就是被别人讨厌。对人而言,最大的不幸就是不喜欢自己。活在“如果怎样怎样”之类的假设之中,就根本无法改变。活在害怕关系破裂的恐惧之中,那是为他人而活的一种不自由的生活方式。人生是连续刹那,我们只能活在“此时此刻”。…...

Python爬虫协程批量下载图片
import aiofiles import aiohttp import asyncio import requests from lxml import etree from aiohttp import TCPConnectorclass Spider:def __init__(self, value):# 起始urlself.start_url value# 下载单个图片staticmethodasync def download_one(url):name url[0].spl…...

Flask Web开发基础:数据库与ORM实战
Flask Web开发基础:数据库与ORM实战 该文介绍了如何使用 Flask、SQLAlchemy 和 SQLite 实现数据库操作。首先,通过创建虚拟环境和安装 flask-sqlalchemy(版本2.5.1)及 sqlalchemy(版本1.4.47)来设置环境。接…...

pidstat -d 1分析磁盘吞吐量
iostat -dx 1 查看磁盘IO吞吐量 pidstat -d 1看是哪个进程写的...

期望20K,2年golang深圳某互联网小公司一面
后续约了二面(CTO面),需要到现场,基本没问啥具体的技术知识,都是聊规划和个人职业目标 一面 1、假设访问百度网站,从在浏览器输入网址,到最终页面展示出来,中间会发生哪些事情&…...

#02 安装指南:如何配置Stable Diffusion环境
文章目录 前言前置条件第1步:安装Python和PIP第2步:创建虚拟环境第3步:安装PyTorch和CUDA第4步:安装Stable Diffusion相关库第5步:测试环境结论 前言 在之前的文章中,我们介绍了Stable Diffusion基础入门和…...

拼多多笔试
拼多多2022数据分析笔试(0822) 一、选择题 1.已知样本量n,样本均值及方差求置信区间 2.决策树 3.峰度系数 4.协方差 5.第一、第二熵变 6.充分统计量 7.xgboost 8.方差分析中的多重比较 二、编程题 1. 一张用户点击路径的表&#x…...

Golang | Leetcode Golang题解之第119题杨辉三角II
题目: 题解: func getRow(rowIndex int) []int {row : make([]int, rowIndex1)row[0] 1for i : 1; i < rowIndex; i {row[i] row[i-1] * (rowIndex - i 1) / i}return row }...

Flutter 中的 SliverIgnorePointer 小部件:全面指南
Flutter 中的 SliverIgnorePointer 小部件:全面指南 Flutter 是一个由 Google 开发的跨平台 UI 框架,它提供了一系列的组件来帮助开发者构建高性能、美观的移动、Web 和桌面应用。在 Flutter 的滚动组件中,SliverIgnorePointer 是一个用来包…...

比较两台计算机上的LabVIEW、工具包及驱动程序的一致性
比较两台计算机上的LabVIEW、工具包及驱动程序是否相同,可以通过以下步骤实现: 1. 检查LabVIEW版本 方法一:在LabVIEW中查看版本信息 步骤: 打开LabVIEW。点击菜单栏的 Help > About LabVIEW。记录显示的LabVIEW版本号和许可…...

参考——温湿度传感器DHT11驱动_STM32
设备:stm32f407ZGT6 环境:FreeRTOS HAL 到网上找DHT11的驱动,但是都无法使用。原因是RTOS环境中,由于多线程,使用循环计数阻塞式的delay_us延时函数就没那么准,且不同设备中delay_us的计数值不一样…...

架构每日一学 14:架构师如何进行可行性探索?
架构活动中,如果不进行可行性探索可能会导致重大失误,为企业发展带来风险。 可行性探索是架构活动的最后一个节点,在这之后的架构活动就像是离弦之箭,即便发现重大风险也很难再回头了。 互联网公司之间的竞争非常激烈࿰…...

多线程知识-13
为什么应该在循环中检查等待条件 为了实现多线程的同步和协调,通常使用等待和唤醒机制。在等待和唤醒机制中,等待条件是指一个线程等待某个条件的满足,当条件满足时,线程被唤醒继续执行。 在循环中检查等待条件的目的是为了避免虚…...

vue3+cli-service配置代理,跨域请求
一、配置代理端口和代理转发 在vue.config.js文件中 const {defineConfig} require(vue/cli-service)module.exports defineConfig({devServer: {host: 0.0.0.0,port: 8088, // 启动端口号proxy: {/api: { // 请求接口中要替换的标识target: , // 代理地址,后…...

git介绍、安装、配置
文章目录 1. GIT介绍2. 使用GIT的好处3. GIT 安装4. GIT 配置4.1 GIT 初始化设置、命令别名设置4.2 如果终端安装了oh-my-zsh,会带一堆git命令别名4.3 GIT配置文件介绍4.3.1 Linux、Mac OS系统4.3.2 windows系统 5. git设置远程仓库账号密码(拉取、上传代码不用输入…...

打开flutter调试
debugPaintSizeEnabled true; debugPaintBaselinesEnabled true;...

【前端 - Vue】Vuex基础入门,创建仓库的详细步骤
🚀 个人简介:6年开发经验,现任职某国企前端负责人,分享前端相关技术与工作常见问题~ 💟 作 者:前端菜鸟的自我修养❣️ 📝 专 栏:vue从基础到起飞 🌈 若有帮助&…...

#01 Stable Diffusion基础入门:了解AI图像生成
文章目录 前言什么是Stable Diffusion?Stable Diffusion的工作原理如何使用Stable Diffusion?Stable Diffusion的应用场景结论 前言 在当今迅速发展的人工智能领域,AI图像生成技术以其独特的魅力吸引了广泛的关注。Stable Diffusion作为其中的一项前沿技术&#…...

Knife4j使用
Knife4j使用 文章目录 Knife4j使用1、Knife4j介绍2、SpringBoot集成Knife4j3、基本使用 1、Knife4j介绍 Knife4j是一个用于生成和展示API文档的工具,同时它还提供了在线调试的功能,可以看作是Swagger的升级版,界面也比Swagger更好看…...

一文读懂银行承兑汇票:从申请到使用全攻略
银行承兑汇票(Banks Acceptance Bill,BA)是商业汇票的一种。它是由在承兑银行开立存款账户的存款人出票,向开户银行申请并经银行审查同意承兑的,保证在指定日期无条件支付确定的金额给收款人或持票人的票据。银行承兑汇…...

唯众智联网(AIoT)应用开发教学实训解决方案
一、引言 随着信息技术的飞速发展,物联网(IoT)和人工智能(AI)技术逐渐融合,形成了智联网(AIoT)这一新兴领域。智联网通过智能化设备、传感器、云计算等技术手段,实现了数…...

归纳跨域几种解决方案
什么是跨域? **说起跨域,就要知道什么是浏览器同源策略 **浏览器同源策略:必须是协议、域名、端口完全一致的才符合同源策略 **如果以上三项,有一项不同都涉及到跨域问题 为什么浏览器要设置同源策略呢? 没有同源策…...

LeetCode刷题第3题(C#)
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串的长度。 法一: 这道题用到的其实是滑动窗口。 滑动窗口算法是在特定窗口大小的数组或字符串上执行要求的操作。它可以将一部分问题中的嵌套循环转变为一个单循环,以此减少时间复…...

了解一下Ubuntu Linux
1.3.1 什么是Ubuntu Ubuntu这个名字非常神奇,它取自非洲南部祖鲁语的ubuntu,是一个哲学名称,其意思为“人性”或者“我的存在是因为大家的存在”。对于中国人来说,一般称呼它为乌班图。 Ubuntu是在Debian的基础上开发出来的&am…...

单一原则+干湿分离,让你的架构能力起飞
# 概念 软件单一原则(Single Responsibility Principle,SRP)是面向对象编程中五大基本设计原则之一。它指每个软件模块或类都应该只负责一个单一的功能或责任。 高内聚低耦合 实现代码可维护性 干湿分离是一种建筑设计和室内装修的方法,主…...

如何恢复永久删除的照片?
“嗨,我永久删除了电脑上的很多照片。回收站被清空,照片会永久丢失吗?有什么方法可以恢复这些已删除的照片吗? 我们所有人都经历过同样的事情:我们的硬盘上存储了文件、视频或照片,但不小心删除了它。这个…...