当前位置: 首页 > news >正文

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都已在图中标注出来,红色为浪费部分。

提示:但是为什么要这个样子呢?为什么要内存对齐?

首先得掌握结构体的对齐规则:

  1. 第一个成员在与结构体变量偏移量为0的地址处存储。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
    VS中默认的值为8
  3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的成员中最大对齐数的整数倍处,结构体的整 体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍

例如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.

接下来就来说一说为什么要对齐!

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

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

对于第二点如下:
在这里插入图片描述

提示:在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到: 让占用空间小的成员尽量集中在一起。
例如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语言结构体的相关知识&#xff0c;包括结构体的基本声明&#xff0c;结构体的匿名结构&#xff0c;结构体的自引用&#xff0c;结构体变量的定义和初始化以及结构体的内存对齐等相关知识。 文章目录 本篇概要1.结构体1.1结构体的基本声明1.2结构体的特殊…...

小程序中如何查看会员的访问记录

​在小程序中&#xff0c;我们可以通过如下方式来查看会员的访问记录。下面是具体的操作流程&#xff1a; 1. 找到指定的会员卡。在管理员后台->会员管理处&#xff0c;找到需要查看访客记录的会员卡。也支持对会员卡按卡号、手机号和等级进行搜索。 2. 查看会员卡详情。点…...

SpringCloud Alibaba - Sentinel

接上文SpringCloud Alibaba - Nacos 1.Sentinel 流量防卫兵 1.1 安装与部署 和Nacos一样&#xff0c;它是独立安装和部署的&#xff0c;下载地址https://github.com/alibaba/Sentinel/releases 下载后的jar放到目录 然后配置 启动并访问,用户名密码都是 sentinel 此时就…...

内存泄漏,内存溢出,抽象类和接口,netstat、ping、ifconfig的区别

持续学习是我们必备的技能之一&#xff0c;保持与时俱进&#xff0c;保持行业的敏感度&#xff0c;关注行业发展趋势&#xff0c;了解新技术&#xff0c;加强自己的认知&#xff0c;积极的应对变化 内存泄漏 memory leak 是指程序在申请内存后&#xff0c;无法释放已申请的内…...

TensorFlow安装 ,在原本的虚拟环境下配置Tensorflow.

1.TensorFlow安装 &#xff0c;在原本的虚拟环境下配置Tensorflowh和pytorch 2.我首先在anaconda的环境下创建了一个tensorflow文件夹 如何先进入D盘&#xff0c;再进入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>主页&#xff1a;&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;Linux——文件系统 ☂️<3>开发环境&#xff1a;Centos7 &#x1f4ac;<4>前言&#xff1a;上期我们了解了文件在内存中得组织方式&#xff0c;那么文件在磁盘中…...

《动手学深度学习 Pytorch版》 7.3 网络中的网络(NiN)

LeNet、AlexNet和VGG的设计模式都是先用卷积层与汇聚层提取特征&#xff0c;然后用全连接层对特征进行处理。 AlexNet和VGG对LeNet的改进主要在于扩大和加深这两个模块。网络中的网络&#xff08;NiN&#xff09;则是在每个像素的通道上分别使用多层感知机。 import torch fr…...

古代有没有电子元器件?

手机&#xff0c;电脑&#xff0c;电视等等电子产品&#xff0c;无时无刻充斥在我们的生活中&#xff0c;如果有一天突然没有了这些功能多样的电子产品&#xff0c;估计大部分人都会一时之间难以适应。 这就好比正在上网&#xff0c;结果突然被人断了网&#xff0c;导致无网络连…...

log4j2或者logback配置模版实现灵活输出服务名

介绍 在我们使用log4j2或者logback打印日志时&#xff0c;输出的内容中通常是一定要加上服务名的。以log4j2为例&#xff1a; <!--输出控制台的配置--> <Console name"Console" target"SYSTEM_OUT"><!-- 输出日志的格式 --><Patter…...

使用HTTP爬虫ip中的常见误区与解决方法

在如今的互联网时代&#xff0c;为了保障个人隐私和实现匿名浏览&#xff0c;许多人选择使用HTTP爬虫ip。然而&#xff0c;由于缺乏了解和使用经验&#xff0c;常常会出现一些误区。本文将为大家介绍使用HTTP爬虫ip过程中常见的误区&#xff0c;并提供相应的解决方法&#xff0…...

MySQL学习笔记3

MySQL的源码编译安装&#xff1a; 1、参考MySQL的源码安装官方文档&#xff1a; 2、源码安装定制选项&#xff1a; 3、源码安装三部曲&#xff1a;配置、编译、安装。 4、软件安装包&#xff1a; mysql-boost-5.7.43.tar.gz 5、安装需求&#xff1a; 安装需求具体配置安装目…...

快速掌握ES6

什么是ES6 ES6&#xff08;ECMAScript 6&#xff09;&#xff0c;也被称为ES2015&#xff0c;是JavaScript的第六个版本&#xff0c;于2015年发布。ES6引入了许多新的语法和功能&#xff0c;旨在提高JavaScript的开发效率和代码质量。 ES6的一些主要特性和改进包括&#xff1…...

电池厂提供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.重载&#xff08;Overload&#xff09;&#xff08;1&#xff09;条件&#xff08;2&#xff09;举例 2.重写&#xff08;Override)&#xff08;1&#xff09;规则&#xff08;2&#xff09;举例 3.重载和重写区别 二、抽象类与接口1.抽象类&…...

Untiy UDP局域网 异步发送图片

同步画面有问题&#xff0c;传图片吧 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 横向滚动列表组件,实现向左滑动

效果&#xff1a; 1.封装组件&#xff1a; <template><div class"scroll-list"><divclass"scroll-list-content":style"{ background, color, fontSize: size }"ref"scrollListContent"><div class"scroll…...

Docker一键安装和基本配置

一键安装脚本 注&#xff1a;该脚本需要root权限 curl -sSL https://get.docker.com/ | sh非root组用户赋权 sudo groupadd docker # 若使用一键安装脚本会自动创建这个组&#xff0c;提示已存在 sudo gpasswd -a ${USER} docker # 将当前用户添加到docker组&#xff0c;也…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

IP如何挑?2025年海外专线IP如何购买?

你花了时间和预算买了IP&#xff0c;结果IP质量不佳&#xff0c;项目效率低下不说&#xff0c;还可能带来莫名的网络问题&#xff0c;是不是太闹心了&#xff1f;尤其是在面对海外专线IP时&#xff0c;到底怎么才能买到适合自己的呢&#xff1f;所以&#xff0c;挑IP绝对是个技…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

破解路内监管盲区:免布线低位视频桩重塑停车管理新标准

城市路内停车管理常因行道树遮挡、高位设备盲区等问题&#xff0c;导致车牌识别率低、逃费率高&#xff0c;传统模式在复杂路段束手无策。免布线低位视频桩凭借超低视角部署与智能算法&#xff0c;正成为破局关键。该设备安装于车位侧方0.5-0.7米高度&#xff0c;直接规避树枝遮…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...

实战设计模式之模板方法模式

概述 模板方法模式定义了一个操作中的算法骨架&#xff0c;并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下&#xff0c;重新定义算法中的某些步骤。简单来说&#xff0c;就是在一个方法中定义了要执行的步骤顺序或算法框架&#xff0c;但允许子类…...

【iOS】 Block再学习

iOS Block再学习 文章目录 iOS Block再学习前言Block的三种类型__ NSGlobalBlock____ NSMallocBlock____ NSStackBlock__小结 Block底层分析Block的结构捕获自由变量捕获全局(静态)变量捕获静态变量__block修饰符forwarding指针 Block的copy时机block作为函数返回值将block赋给…...