C语言自定义类型详解(1)结构体知识汇总
本篇概要
本篇主要讲述C语言结构体的相关知识,包括结构体的基本声明,结构体的匿名结构,结构体的自引用,结构体变量的定义和初始化以及结构体的内存对齐等相关知识。
文章目录
- 本篇概要
- 1.结构体
- 1.1结构体的基本声明
- 1.2结构体的特殊声明(匿名结构体类型)
- 1.3结构体的自引用
- 1.4结构体变量的定义和初始化
- 1.5结构体内存对齐
- 1.6结构体传参
1.结构体
1.1结构体的基本声明
结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。
结构体的基本用法如下:
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢
当然,我在这里还有一些补充
struct student
{
}s1,s2,s3;//这s1,s2,s3是三个结构体变量int main()
{
struct student s4,s5,s6;//s4,s5,s6是三个结构体变量
return 0;
}
需要说明的是s1,s2,s3是全局变量,s4,s5,s6是局部变量。
1.2结构体的特殊声明(匿名结构体类型)
struct
{char neme[20];int age;char sex[5];//一个汉字2个字符float score;
}s1,s2;
↑如上代码所示,可以去掉结构体的名字 匿名结构体类型,但只能用一次,后面再想定义变量不可以(只可以使用s1和s2)
struct
{char neme[20];int age;char sex[5];//一个汉字2个字符float score;
}b;struct
{char neme[20];int age;char sex[5];//一个汉字2个字符float score;
}*p;int main()
{
p=&b;
return 0;
}
↑这里,两个结构体类型完全一样,但是p=&b这样是有问题的,虽然结构体类型,成员完全一样,但在编译器看来,这依然是两种结构体类型,编译器认为p和&b是不一样的。
1.3结构体的自引用
即在结构中包含一个类型为该结构本身的成员
自引用错误用法:
struct Node
{
int data;
struct Node n;
};int main()
{
printf("%d",sizeof(struct Node));
return 0;
}
提示:这么使用编译器会报警,运行不成功。因为struct中有一个整形为4字节,后面有一个结构体,那么是4+n,那么n中又是4+n,算不了。
自引用的正确用法:
struct Node
{
int data;
struct Node* n;
};
int main()
{
printf("%d",sizeof(struct Node));
return 0;
}
此时,代码可以运行,用指针的话,指针存放下一个节点的地址,指针本身的大小也是固定的,所以可以计算出来。
1.4结构体变量的定义和初始化
下面列举几种结构体的定义:
struct Point
{int x;int y;
}p1 = {1,2};struct Point p3 = {4,5};int main()
{int a = 10;int b = 20;struct Point p2 = {a, b};return 0;
}
结构体可以这么定义
struct Stu
{char name[15];//名字int age;
};
struct Stu s = { "zhangsan", 20 };
struct Stu s2 = { .age=18, .name="如花"};int main()
{
printf("%s %d\n", s.name, s.age);
printf("%s %d\n", s2.name, s2.age);
}
也可以这么定义
struct Node
{int data;struct Point p;struct Node* next;
};
int main()
{
struct Node n = { 100, {20, 21}, NULL };
printf("%d x=%d y=%d\n", n.data, n.p.x, n.p.y);
}
更加复杂,也还可以这么定义,嵌套结构体。
1.5结构体内存对齐
我们先来看以下的代码:
struct S1
{char c1;int i;char c2;
};struct S2
{char c1;char c2;int i;
};int main()
{printf("%d\n", sizeof(struct S1));printf("%d\n", sizeof(struct S2));return 0;
}

提示:我们可以看到两个一摸一样的结构体,计算出来的大小,却不一样,这是什么导致的呢?
就是结构体的内存对齐导致的。
下来给大家介绍一个宏 offsetof,其头文件为<stddef.h>
它可以计算结构体成员相较于起始位置的偏移量
我们在上面代码的main函数加上以下代码:
int main()
{printf("%d\n", offsetof(struct S1, c1));printf("%d\n", offsetof(struct S1, c2));printf("%d\n", offsetof(struct S1, i));//printf("%d\n", sizeof(struct S1));//printf("%d\n", sizeof(struct S2));return 0;
}


我们可以看到offsetof计算出来的结果为0,4,8,上面的示意图对应的就是struct内存的结构,灰色为char c1,蓝色为int i,橙色为char c2,红色的取余浪费了。
使用同样的操作,我们可以得出struct的结构示意图。

c1,c2,i都已在图中标注出来,红色为浪费部分。
提示:但是为什么要这个样子呢?为什么要内存对齐?
首先得掌握结构体的对齐规则:
- 第一个成员在与结构体变量偏移量为0的地址处存储。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8- 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的成员中最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
例如struct s2
char c1偏移量为0 ,直接占第一个字节
char c2 偏移量为min{1,8}
int i 偏移量为min{4,8}
此结构体最大对齐数位4,根据规则三结构体总大小取4的整数倍,即8.再例如struct s1
char c1偏移量位0,直接占第一个字节
int i偏移量位min{4,8},从第四个字节开始占4个字节
char c2,偏移量为1的倍数,直接放在i后面
这是一共占了9个字节,最大对齐数为4,结构体大小应为4的倍数,故为12.
接下来就来说一说为什么要对齐!
- 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特 定类型的数据,否则抛出硬件异常。
- 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
结构体的内存对齐是拿空间来换取时间的做法。
对于第二点如下:
提示:在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到: 让占用空间小的成员尽量集中在一起。
例如struct s2就比struct s1所占空间小!!
上面讲到VS的默认对齐数为8,我们也可以更改它
pragma pack(5) //设置默认对齐数为5
pragma pack() //取消设置的默认对齐数,还原为默认
1.6结构体传参
代码使用了结构体传值调用和传址调用两种方法:
struct S
{int data[1000];int num;
};void print1(struct S t)
{printf("%d %d %d %d\n", t.data[0], t.data[1], t.data[2], t.num);
}void print2(const struct S * ps)
{printf("%d %d %d %d\n", ps->data[0], ps->data[1], ps->data[2], ps->num);
}int main()
{struct S s = { {1,2,3}, 100 };print1(s);//传值调用print2(&s);//传址调用return 0;
}
函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的 下降。所以我们优先使用传址调用。
相关文章:
C语言自定义类型详解(1)结构体知识汇总
本篇概要 本篇主要讲述C语言结构体的相关知识,包括结构体的基本声明,结构体的匿名结构,结构体的自引用,结构体变量的定义和初始化以及结构体的内存对齐等相关知识。 文章目录 本篇概要1.结构体1.1结构体的基本声明1.2结构体的特殊…...
小程序中如何查看会员的访问记录
在小程序中,我们可以通过如下方式来查看会员的访问记录。下面是具体的操作流程: 1. 找到指定的会员卡。在管理员后台->会员管理处,找到需要查看访客记录的会员卡。也支持对会员卡按卡号、手机号和等级进行搜索。 2. 查看会员卡详情。点…...
SpringCloud Alibaba - Sentinel
接上文SpringCloud Alibaba - Nacos 1.Sentinel 流量防卫兵 1.1 安装与部署 和Nacos一样,它是独立安装和部署的,下载地址https://github.com/alibaba/Sentinel/releases 下载后的jar放到目录 然后配置 启动并访问,用户名密码都是 sentinel 此时就…...
内存泄漏,内存溢出,抽象类和接口,netstat、ping、ifconfig的区别
持续学习是我们必备的技能之一,保持与时俱进,保持行业的敏感度,关注行业发展趋势,了解新技术,加强自己的认知,积极的应对变化 内存泄漏 memory leak 是指程序在申请内存后,无法释放已申请的内…...
TensorFlow安装 ,在原本的虚拟环境下配置Tensorflow.
1.TensorFlow安装 ,在原本的虚拟环境下配置Tensorflowh和pytorch 2.我首先在anaconda的环境下创建了一个tensorflow文件夹 如何先进入D盘,再进入tensorflow文件夹的目录D:cd D:\Anaconda\TensorFlowSoftWarepip install tensorflow如图所示报错解决方法 …...
如何使用HTML, CSS和JavaScript开发一个浏览器打字游戏:从零到一的详细步骤与完整代码教程
第一部分:游戏概述与HTML结构 1. 游戏概述 打字游戏是一个训练用户打字速度和准确性的游戏。用户将会看到一个随机的单词或句子,并在限定时间内尽快准确地键入该单词或句子。每次正确输入,玩家得分,每次输入错误,扣分。这个游戏不仅能够增加用户的打字速度,还可以为学习…...
安卓玩机搞机----不用刷第三方官改固件即可享受“高级设置”的操作 ChiMi安装使用步骤
很多玩友特别喜欢第三方作者修改的带有高级设置的官改包。因为他可以随意修改系统里面的有关设置选项。包括但不限于修改状态栏 显示日期 秒等等的操作。 第三方带高级设置的官改 一般官改带高级设置的类似与 今天给大家分享下不用刷这些官改包即可享受高级设置的操作。 红米…...
代码随想录|392.判断子序列,115.不同的子序列(需要二刷)
392.判断子序列 先用双指针做 class Solution {public boolean isSubsequence(String s, String t) {//双指针int ms.length();int nt.length();int slow0;int i0;int j0;while(i<m&&j<n){if(s.charAt(i)t.charAt(j)){i;System.out.println(i);}j;}return im?…...
Linux——文件系统
✅<1>主页::我的代码爱吃辣 📃<2>知识讲解:Linux——文件系统 ☂️<3>开发环境:Centos7 💬<4>前言:上期我们了解了文件在内存中得组织方式,那么文件在磁盘中…...
《动手学深度学习 Pytorch版》 7.3 网络中的网络(NiN)
LeNet、AlexNet和VGG的设计模式都是先用卷积层与汇聚层提取特征,然后用全连接层对特征进行处理。 AlexNet和VGG对LeNet的改进主要在于扩大和加深这两个模块。网络中的网络(NiN)则是在每个像素的通道上分别使用多层感知机。 import torch fr…...
古代有没有电子元器件?
手机,电脑,电视等等电子产品,无时无刻充斥在我们的生活中,如果有一天突然没有了这些功能多样的电子产品,估计大部分人都会一时之间难以适应。 这就好比正在上网,结果突然被人断了网,导致无网络连…...
log4j2或者logback配置模版实现灵活输出服务名
介绍 在我们使用log4j2或者logback打印日志时,输出的内容中通常是一定要加上服务名的。以log4j2为例: <!--输出控制台的配置--> <Console name"Console" target"SYSTEM_OUT"><!-- 输出日志的格式 --><Patter…...
使用HTTP爬虫ip中的常见误区与解决方法
在如今的互联网时代,为了保障个人隐私和实现匿名浏览,许多人选择使用HTTP爬虫ip。然而,由于缺乏了解和使用经验,常常会出现一些误区。本文将为大家介绍使用HTTP爬虫ip过程中常见的误区,并提供相应的解决方法࿰…...
MySQL学习笔记3
MySQL的源码编译安装: 1、参考MySQL的源码安装官方文档: 2、源码安装定制选项: 3、源码安装三部曲:配置、编译、安装。 4、软件安装包: mysql-boost-5.7.43.tar.gz 5、安装需求: 安装需求具体配置安装目…...
快速掌握ES6
什么是ES6 ES6(ECMAScript 6),也被称为ES2015,是JavaScript的第六个版本,于2015年发布。ES6引入了许多新的语法和功能,旨在提高JavaScript的开发效率和代码质量。 ES6的一些主要特性和改进包括࿱…...
电池厂提供excel电池曲线zcv到mtk电池曲线zcv转换
#encoding:utf8 #电池厂提供excel电池曲线zcv到mtk电池曲线zcv转换 import pandas as pd import openpyxl import math # 读取Excel文件 df pd.read_excel("a55-zcv.xlsx") for j in range(0,10): if(j<3): offset0 #T0~T2 if(j3): offset…...
重写和重载、抽象类和接口
文章目录 前言一、重载与重写1.重载(Overload)(1)条件(2)举例 2.重写(Override)(1)规则(2)举例 3.重载和重写区别 二、抽象类与接口1.抽象类&…...
Untiy UDP局域网 异步发送图片
同步画面有问题,传图片吧 using System.Text; using System.Net.Sockets; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using System.Net; using System; using System.Threading.Tasks; using Sy…...
移动端H5封装一个 ScrollList 横向滚动列表组件,实现向左滑动
效果: 1.封装组件: <template><div class"scroll-list"><divclass"scroll-list-content":style"{ background, color, fontSize: size }"ref"scrollListContent"><div class"scroll…...
Docker一键安装和基本配置
一键安装脚本 注:该脚本需要root权限 curl -sSL https://get.docker.com/ | sh非root组用户赋权 sudo groupadd docker # 若使用一键安装脚本会自动创建这个组,提示已存在 sudo gpasswd -a ${USER} docker # 将当前用户添加到docker组,也…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...
