自定义类型:结构体进阶学习分享

自定义类型:结构体进阶学习分享

  • 前言
  • 1 结构体的基础知识
  • 2 结构的声明
  • 3 特殊声明
  • 4 结构的自引用
  • 5 结构体变量的定义和初始化
  • 6 结构体内存对齐
    • 6.1 计算结构体大小相关笔试题(基于VS)
      • 笔试题一:
      • 笔试题二:
    • 6.2 为什么存在内存对齐?
    • 6.3 如何设计结构体减少空间
  • 1.7 修改默然对齐数
  • 8. 结构体传参
  • 9. 结尾

前言

结构体在C语言中具有重要的意义。它不仅可以封装和组织数据,还可以提供抽象和封装的能力,方便数据的传递和操作,提高代码的可读性和可维护性,是C语言中常用的数据类型之一。本篇博客将详细介绍相关知识。

1 结构体的基础知识

在结构体初阶我们以及详细介绍过了有关结构体的基础。

结构是一些值的集合,这些值被称为成员变量。结构的每一个成员可以是不同类型的变量。

2 结构的声明

struct tag
{member-list;
}variabe-list;

例如描述一个学生:

struct Stu
{char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号
};

3 特殊声明

在声明结构体的时候,可以不完全声明。(匿名结构体声明)
比如:

//匿名结构体
struct
{int a;char b;float c;
}x;
struct
{int a;char b;float c;
}*px;

上面的两个结构在声明的时候省略掉了结构体标签(tag)。
那问题来了?

//在上面代码的基础上,下面的代码合法吗?
px = &x;

警告:

  • 编译器会将上面的两个声明当成完全不同的两个类型。所以是非法的。

4 结构的自引用

在结构中包含一个类型为该结构本身的成员是否可以呢?

struct Node//err,比如计算其大小sizeof(struct Node)时,大小是不确定的
{int date;struct Node next;
};//正确的自引用方法
struct Node
{int date;struct Node* next ;
};

注意: 上面结构体类型有时过于冗杂,我们可以采用重命名。

//我们知道结构体可以匿名。那是否可以重命名呢?
//答案是否定的。
//例如下面这段代码,结构体中的Node* next变量还没有创建成功,结构体不是完整的,因此不可重命名
typedef struct//err
{int date;Node* next;
}Node;//正确使用
typedef struct Node
{int date;struct Node* next;
}Node;

5 结构体变量的定义和初始化

有了结构体类型,那如何定义和初始化呢?其实很简单。

struct Stu	//声明类型
{char name[15];//名字int age;//年龄
};
struct Stu s = { "zhangsan",20 };//初始化struct Point
{int x;int y;
};
struct Node
{int date;struct Point p;struct Node* next;
}n1 = { 10, {4,5}, NULL };//结构体嵌套初始化

6 结构体内存对齐

接下来我们将介绍一个热门考点:结构体内存对齐
结构体内存对齐规则:

1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数与该成员大小的 较小值
。vs默认的值为8
。Linux中没有默认对齐数,对齐数就是成员自身的大小

3. 结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

6.1 计算结构体大小相关笔试题(基于VS)

笔试题一:

#include <stdio.h>struct S1
{char c1;//对齐到偏移量为0处int i;//int占4个字节,VS默认对齐数为8;所以对齐数为最小值:4字节//所以int对齐到偏移量为4后在向后移动4个字节即为。该位置即是int在内存中占据的空间char c2;//同理char的对齐数为1。在int后移动一个字节即可。
};
//上述结构体struct S1共占据9个字节,而结构体的大小必须是最大对齐数4(本题中,对齐数分别为1,4,1)的整数倍
//所以结构体还需向内存申请3个字节空间大小,及总大小为12字节。struct S2
{char c1;//第一个变量成员对齐到偏移量为0处char c2; //该变量对齐数为1(char为1byte, VS默认为9byte,取最小值)//即在变量c1后申请1字节即可int i;//该变量对齐数为4(int为4byte, VS默认为9byte,取最小值)//所以变量i对齐到偏移量为4处,在向后申请4个字节即可。
};//到此结构体总共向内存申请了8byte, 为最大对齐数4(本题中三个变量对齐数分别为:1,1,4)的整数倍。//所以该结构体的最终大小为8int main()
{printf("%d\n", sizeof(struct S1));printf("%d\n", sizeof(struct S2));return 0;
}

运行结果:
在这里插入图片描述
—————————————————————————————————————

笔试题二:

struct S3
{double d;//第一个成员变量对齐到偏移量为0处,在向后申请8字节(double大小为8)char c;//该成员变量对齐数为1(char为1byte,VS默认对齐数为8,取最小值)//所以变量对齐到偏移量为8处,向后申请1byteint i;//该成员变量对齐数为4(int为4byte,VS默认对齐数为8,取最小值)//所以该变量首先要对齐到偏移量为12的位置(必须对齐到4的整数倍处),在向后申请4个字节
};
//到此该结构体向内存共申请了16字节,为最大对齐数8的整数倍
//所以该结构体的最终大小为16bytestruct S4
{char c1;//第一个成员变量对齐到偏移量为0处,在向后申请1字节(char大小为1)struct S3 s3;//嵌套结构体,结构体要对齐到自己最大对齐数8(上面已经求得最大对齐数为:8)的整数倍处。即该成员变量对齐到偏移量为8出,在向后申请16字节(上面已经求出其大小16byte)double d;//该成员变量对齐数为8(double为8byte,VS默认对齐数为8,取最小值)//上述两个变量总共为24个字节,所以该成员变量从偏移量为24(刚好为8得整数倍)开始,在向后申请8字节
};
//到此该结构体总共占据32个字节空间,为最大对齐数8(上述3个成员变量对齐数分别为:1,8,8)的整数倍。
//所以最终该结构体总大小为32byteint main()
{printf("%d\n", sizeof(struct S3));printf("%d\n", sizeof(struct S4));return 0;
}

运行结果:
在这里插入图片描述

6.2 为什么存在内存对齐?

大部分参考资料是这么说的:

1.平台原因(移植原因)
不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处去某些特定类型的数据,否则抛出硬件异常。
2. 性能原因
结构数据(尤其是栈)应尽可能地在自然边界上对齐。
原因在于为了访问未对其的内存,处理器需要作两次内存访问;而对齐的内存仅需要一次访问。

总的来说:

结构体的内存对齐是拿空间来换时间的做法。

6.3 如何设计结构体减少空间

在设计结构体时,我们既要满足对齐,又要节省空间,如何做到呢?

我们前面已经见过这段代码:

struct S1
{char c1;int i;char c2;
};
struct S2
{char c1;char c2; int i;
}
int main()
{printf("%d\n", sizeof(struct S3));//12printf("%d\n", sizeof(struct S4));//8return 0;
}

S1和S2类型的成员一模一样,但是S1和S2所占据的空间大小有一些区别。我们可以得到:

  • 在设计结构体时,尽量让占用空间小的成员尽量集中在一起,从而节省空间。

1.7 修改默然对齐数

#pragma这个预处理指令可以被用来修改我们的默认对齐数。

#include <stdio.h>#pragma pack(8)//设置默认对齐数为8
struct S1
{char c1;int i;char c2;
};
#pragma pack()//取消默认对齐数#pragma pack(1)//设置默认对齐数为1
struct S2
{char c1;int i;char c2;
};
#pragma pack()//取消默认对齐数int main()
{printf("%d\n", sizeof(struct S1));printf("%d\n", sizeof(struct S2));return 0;
}

运行结果:
在这里插入图片描述
总结:

  • 结构在对齐方式不合适说的时候,我们可以自己更改默认对齐数。

8. 结构体传参

直接上代码:

#include <stdio.h>
struct S
{int date[1000];int num;
};
struct S s = { {1,2,3,4}, 1000 };//结构体传参
void print1(struct S s)
{printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* s)
{printf("%d\n", s->num);
}int main()
{print1(s);print2(&s);return 0;
}

上面print1和print2函数那个更好?
答案是:首选print2函数。
原因:

函数传参的时候,参数是需要压栈的,会有时间和空间上的开销。
如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大,所以会导致性能的下降。

结论:

结构体传参时,要传结构体指针。

9. 结尾

本篇博客到此就结束了。传作不易,如果对你有帮助记得三连哦!感谢您的支持!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/6036.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FFmpeg 命令行实现居中高清上下模糊播放效果

FFmpeg 命令行实现居中高清上下模糊播放效果。 1、16:9 的横屏原视频&#xff0c;以 16:9 竖屏上下模糊播放 以该效果播放视频的命令如下&#xff1a; ffplay -i horizontal_test_video_169.mp4 -vf \ "split[a][b]; \ [a]crop(ih/16*9):ih,scaleiw/10:-1,gblursigma5…

深度理解 Spring AOP

一、什么是AOP(面向切面编程)&#xff1f;&#x1f349; AOP 为 Aspect Oriented Programming 的缩写&#xff0c;意思为面向切面编程&#xff0c;是通过预编译方式 和运行期 动态代理 实现程序功能的统一维护的一种技术。 AOP &#xff08;面向切面编程&#xff09;是 OOP&a…

代码随想录额外题目| 数组02 ●189旋转数组 ●724寻找数组中心索引

#189旋转数组 很快写出来但是用了个新数组&#xff0c;不好 void rotate(vector<int>& nums, int k) {vector<int> res(nums.size(),0);for(int i0;i<nums.size();i){int newiik;if(newi>nums.size()-1) newinewi%nums.size();res[newi]nums[i];}numsr…

vue组件(个人学习笔记三)

目录 友情提醒第一章、vue的组件1.1&#xff09;什么是SPA应用1.2&#xff09;vue的组件简介1.3&#xff09;vue工程中的main.js文件 第二章、Vue组件的使用2.1&#xff09;一般组件的自定义2.2&#xff09;注册组件&#xff1a;全局注册和局部注册2.2.1&#xff09;全局注册&a…

和chatgpt学架构04-路由开发

目录 1 什么是路由2 如何设置路由2.1 安装依赖2.2 创建路由文件2.3 创建首页2.4 编写HomePage2.5 更新路由配置2.6 让路由生效 3 测试总结 要想使用vue实现页面的灵活跳转&#xff0c;其中路由配置是必不可少的&#xff0c;我们在做开发的时候&#xff0c;先需要了解知识点&…

Vue--》打造个性化医疗服务的医院预约系统(二)

今天开始使用 vue3 + ts 搭建一个医院预约系统的前台页面,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关…

基于Python+多层RNN+Tensorflow藏头诗与歌词智能生成-深度学习算法应用(含全部工程源码)+训练数据集

目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境Tensorflow 环境PyCharm环境 模块实现古诗生成1. 数据预处理2. 模型构建3. 模型训练及保存4. 使用模型生成古诗5. 产生藏头诗6. 用词云展示生成的古诗 歌词生成1. 数据预处理2. 模型构建3. 模型训练并保存4. 生成…

基于Kitti数据集的智能驾驶目标检测系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于Kitti数据集的智能驾驶目标检测系统可用于日常生活中检测与定位行人&#xff08;Pedestrian&#xff09;、面包车&#xff08;Van&#xff09;、坐着的人&#xff08;Person Sitting&#xff09;、汽车&#xff08;Car&#xff09;、卡车&#xff08;Truck…

【字符流】案例:文件到集合

案例&#xff1a;文件到集合 1.需求&#xff1a; 把文本文件中的数据读取到集合&#xff0c;并遍历集合。要求&#xff1a;文件中的每一行数据是一个集合元素 2.思路 创建字符缓冲输入流对象创建ArrayList集合对象调用字符缓冲输入流对象的方法读数据把读取到的字符串数据存…

Java IO

stream 流 是一种抽象概念&#xff0c;它代表了数据的无结构化传递。按照流的方式进行输入输出&#xff0c;数据被当成 无结构的字节序或字符序列。从流中取得数据的操作称为提取操作&#xff0c;而向流中添加数据的操作称为插入操作。用来进行输入输出操作的流就称为IO 流。换…

spring复习:(50)@Configuration注解配置的singleton的bean是什么时候被创建出来并缓存到容器的?

一、主类&#xff1a; 二、配置类&#xff1a; 三、singleton bean的创建流程 运行到context.refresh(); 进入refresh方法&#xff1a; 向下运行到红线位置时&#xff1a; 会实例化所有的singleton bean.进入finisheBeanFactoryInitialization方法&#xff1a; 向下拖动代…

JavaWeb课程设计项目实战(06)——项目编码实践3

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 在本教程教程中&#xff0c;我们实现学生列表的显示。 Student 请在bean包下创建Student类&#xff0c;代码如下&#xff1a; package com.cn.bean; /*** 本文作者&#…

数据科学团队的角色分工

描述数据科学团队中角色分工常用下列维度。进一步以数据可视化直观表达的能力雷达图: ML Ops - 机器学习运维 Data Pipelines - 数据流水线 Database - 数据库 Data Viz - 数据可视化 Storytelling - 数据讲故事 Business Insights - 业务洞察 Reporting - 报告 Experimentatio…

【100天精通python】Day10:函数的创建和调用,参数传递,返回值,变量作用域以及匿名函数

目录 1. 函数的创建和调用 1.1 函数的创建 1.2 调用函数 2 参数传递 2.1 传递方式 2.2 形参和实参 2.3 位置参数 2.4 关键字参数 2.5 可变参数 2.6 为参数设置默认值 3 返回值 4 变量的作用域 4.1 局部变量 4.2 嵌套变量 4.3 全局变量 5 匿名函数&#xff0…

X86设备启动过程

文章目录 一、电源自检二、BIOS自检三、引导设备选择四、主引导记录4.1 0x7c0 五、加载操作系统 x86计算机启动过程&#xff0c;主要分为这几个阶段&#xff1a;电源自检、BIOS自检、引导设备的选择、主引导记录、加载操作系统。 一、电源自检 当我们按下开关键后&#xff0c;…

uni-app image加载错误 404 替换为默认图片

双层v-for 使用item修改 aitem.cat_icon || defaultPic绑定图片src属性为aitem.cat_icon 如果aitem.cat_icon的值为空字符串或undefined&#xff0c;那么默认图片defaultPic被显示出来当图片加载错误时,触发handleImageError方法,将aitem传进去 <!-- 页面--><view …

Java 知识合集 | 多线程与并发

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

直接插入排序、希尔排序、直接选择排序、堆排序、冒泡排序——“数据结构与算法”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰的内容是数据结构与算法啦&#xff0c;是排序&#xff01;&#xff01;&#xff01;下面&#xff0c;让我们进入七大排序的世界吧&#xff01;&#xff01;&#xff01; 排序的概念及其运用 排序的概念 排序&#xff1a;所谓排序…

19 数组静态初始化练习

语法&#xff1a; 数据类型[ ] 数组名称 {元素1&#xff0c;元素2&#xff0c;元素3}; public class Demo1 {public static void main(String[] args) {int[] arr {0,1,2,3};System.out.println(arr);System.out.println(arr[0]);System.out.println(arr[1]);System.out.pri…

SpringBoot中间件—ORM(Mybatis)框架实现

目录 定义 需求背景 方案设计 代码展示 UML图 实现细节 测试验证 总结 源码地址&#xff08;已开源&#xff09;&#xff1a;https://gitee.com/sizhaohe/mini-mybatis.git 跟着源码及下述UML图来理解上手会更快&#xff0c;拒绝浮躁&#xff0c;沉下心来搞 定义&#x…