C语言自定义类型结构体

 

variable

adj.易变的,多变的;时好时坏的;可变的,可调节的;

(数)(数字)变量的;(植,动)变异的,变型的;(齿轮)变速的

n.可变性,可变因素;(数学中的)变量,变元;

(计算机)变量(元);(天文)变星的简称;

(东北信风带以北或南半球的东南信风带与西风带之间的)变风区

前言:

在一开始学习C语言时,我们学习的是int,char...(内置类型),之后又学习数组(自定义类型),然后又学习了指针类型,基本的类型我们都学习的差不多了,今天在为大家带来自定义类型中的三大类型:结构体类型、共用体类型和枚举类型。

1.定义

结构体其实就是各种类型数据的结合体。

比如:对于一个学生而言,学生的属性就有他的名字,性别,年级,成绩等等,为了将这些属性都存储在一起,这时就需要新的自定义类型来进行将不同类型的数据进行整合,这就是结构体类型。

2.创建方式

 ⚀声明方式:

struct  str_name
{
    number_var;
    number_var;
    ...
};
  • struct        创建结构体类型时的关键字        
  • str_name        struct_name结构体类型的名字
  • number_var        number_varible结构体内的成员变量

注意:

  1. 结构体类型的成员变量不能被初始化
  2. struct str_name这两个合在一起才被称为结构体类型。
  3. 结构体的声明一定在使用前进行声明不能在后声明。
  4. 结构体成员变量可以是任何类型,但绝对不可以成员变量含有自身结构体结构体。

        对于这种结构体是不允许创建的,因为你的结构体成员里面的又有自身的结构体,你这个成员变量的结构体里面又含有结构体,如此下去,结构体里含结构体,那么这个结构体的大小的有多大?答案是:不知道,很大很大很大!!!大到溢出!!!所以这种方式是不允许的!!! 

例子:

//以一个学生为例,声明一个结构体
struct Stu
{
    char name;//名字
    int age;//年龄
    int height;//体重
    int arr[10];//各科的成绩
}

typedef重命名

//以一个学生为例,声明一个结构体
typedef struct Stu //定义的结构体前加上typedef关键字
{
    char name;//名字
    int age;//年龄
    int height;//体重
    int arr[10];//各科的成绩
}Stu;//在定义完后面加上重新命名的名字
struct Stu S1;//使用struct定义的名字创建变量
Stu S2;//使用typedef重命名的名字创建变量
//不在声明时重命名
typedef struct Stu Stu;//typedef关键字+原名+新名字;

变量创建方式:

A.在声明时

//以一个学生为例,声明一个结构体
struct Stu 
{
    char name;//名字
    int age;//年龄
    int height;//体重
    int arr[10];//各科的成绩
}S1,S2,S3;
//在声明完结构体后,在后面接着创建结构体变量

B.通过结构体类型

//以上面的struct Stu结构体为例
struct Stu S1;//通过结构体类型创建结构体变量

 特殊声明:

struct    //不声明结构体类型名字
{
    char name;//名字
    int age;//年龄
    int height;//体重
    int arr[10];//各科的成绩
}S1;//创建结构体变量
  • 这种在声明结构体时不声明结构体类型名,而在声明后接着创建结构体变量的操作就称为结构体的匿名声明。
  • 对于这种没有将结构体类型名的结构体,就意味着不能通过结构体类型来创建结构体变量,这种只能使用它后面的结构体变量,可以称为一次性结构体。

 自引用:

        在结构体声明时,我们讨论过不能在结构体内部创建自身的结构体变量进行使用,因为会使得结构体内存大小溢出,那么有什么方法可以实现能在结构体中自引用自己这个结构体呢?

答案是:自己的结构体指针

3.使用方式

访问成员操作:

A.操作符' . '

结构体变量名.成员变量名

str_name.number_var_name1
S1.age = 21;

通过结构体类型变量访问

B.操作符" -> "

结构体指针->成员变量名

str_piont_name.number_var_name1
struct Stu* p;//结构体指针
p->age = 21;

通过结构体指针变量访问 

初始化操作:

按照结构体变量初始化的位置分:

A.在声明时创建变量时

B.通过结构体类型创建时

按照成员变量初始化的顺序分:

A.声明时顺序初始化:

B.指定顺序初始化:

结构体的传值or传址 ?

        由于结构体在内存中的存储满足内存对齐,就会存在内存浪费,加之结构体时多种的数据类型的集合,内存空间就会非常大,就不推荐使用传值调用,会拷贝数据压栈(在栈区上开辟空间,会浪费空间,溢出等),所以结构体进行调用时最好时传址调用。

4.存储方式

        首先我们来看一下下面这个结构体的内存大小:

Why?为啥不是6个字节,不是这几个类型得字节数相加?难道是2倍关系 ?

其实小编可以告诉大家不是啦,结构体在内存中得存储是一种新的方式:内存对齐

那么下面让我们一起看一下什么是内存对齐,小编先为大家介绍内存对齐的规则,嘻嘻

内存对齐规则:

假设有段内存空间,结构体就存储在这上面,那么在存储前先要对这块空间的内存单元进行编号,而成员变量的存储方式就与这些编号有关,这种方式就是内存对齐。

  1. 第一个成员变量默认从编号0的位置开始存储。
  2. 后面的成员变量对齐的编号(对齐数)是{编译器默认的对齐数,成员变量的大小(字节)}min的整数倍。
  3. 最后结构体的内存空间大小还需满足是:{编译器默认的对齐数,成员变量的大小(字节)}min的整数倍。

注意:

  • 如果是结构体里面含有结构体,那么不是按照这结构体的大小去和编译器默认的对其数比较,而是该结构体内部最大的成员变量的字节数去进行比较。
  • VS编译器默认的对其数是8,gcc编译器没有默认的对齐数,对其数就是成员变量本身。

例子:

结构体里嵌套结构体

修改默认对齐数:

对于VS编译器,我们可以通过#pragma操作修改默认对其数:

对其数为8时
对其数为1时

为什么存在内存对齐? 

【补充】

结构体的内存对齐是为了**提高数据访问的效率以及满足特定硬件和操作系统的要求**。具体原因包括:

  1. 性能优化:CPU访问内存时,对齐的内存可以更快被读取。不对准的内存访问可能会导致多次内存访问才能获取全部数据,降低效率。
  2. 硬件要求:某些硬件平台要求特定的数据类型必须在特定地址边界上开始,如2的幂次方边界(4字节、8字节等)。
  3. 减少填充:对齐可以减少或消除数据结构中的填充字节,使得结构更紧凑,节省内存空间。
  4. 跨平台兼容性:不同的系统可能有不同的对齐要求,对齐可以确保代码在不同平台上的一致性和兼容性。
  5. 指令集优化:某些CPU指令集在处理对齐数据时更为高效,因此对齐可以提高指令执行的速度。
  6. 缓存机制:现代CPU的缓存机制通常以特定的对齐边界来存储和检索数据,对齐有助于提高缓存命中率。
  7. 数据结构对齐规则:结构体的第一个成员与结构体的起始地址对齐,其他成员根据其类型的最大对齐要求进行对齐。
  8. 默认对齐数:编译器通常有默认的对齐数值,但可以通过编译器指令或特定的编译器选项来修改。
  9. offsetof宏:在处理结构体时,`offsetof`宏可以用来获取成员在结构体中的偏移量,这对于理解和操作结构体非常有用。

综上所述,结构体的内存对齐是计算机编程中的一个重要概念,它关系到程序的性能、硬件兼容性以及代码的可维护性。了解并正确应用内存对齐规则,对于编写高效且健壮的程序至关重要。

【转载自百度】

5.位段

定义:

  • 结构体的位段是一种特殊类型的成员,它允许程序以bit(比特位)为单位来定义结构体成员变量在内存中所占空间的大小。
  • 位段的定义是在成员变量后面+冒号+大小(比特位)进行限定大小。
  • 成员必须是int,unsigned int或[signed] char,在C99标准中也可以使用其他类型。
  • 位段的主要目的是节约存储空间。
int a:5;
char b:3;

存储方式:

  1. 含有位段的结构体进行存储时,按需来开辟空间的,如果是int类型就开4个字节,char类型就开1个字节
  2. 位段成员是优先存为上个位段开辟空间里,如果下个位段成员存不进上一个位段成员开辟的空间,是舍弃空间还是利用空间是无法确定的。
  3. 多个位段是可能共用同一块内存空间的。
  4. 因为只有内存单元有地址,那么对于位段的成员变量的存储是从内存单元的左边开始存还是右边开始存是未知的

下面以VS编译器为例:


 

正确解析
错误解析

注意事项:

  • 位段中最大位的数目不能确定,比如16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。
  • 通过前面的分析,在位段的存储方式上和最大位数上有很大的不确定性,所以位段是不跨平台的,注重可移植的程序应该避免使⽤位段。
  • 位段是按位存储的,所以对于位段成员的结构体,不要用scanf取地址存数值,存的数值可能会被截取,就不是想要的数据。

本章内容结束,下章见,拜拜!!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【阿里云物联网】上报设备数据

前言 MQTT客户端上传数据到阿里云服务端,并且能将数据显示出来。在此之前,我们先要懂得阿里云给设备管理划分的概念。首先是产品,所以在产品里要配置内容,产品下的设备才可以使用,比如主题大类都是在产品里面就可以查…

优惠:阿里云4核16G服务器优惠价格26.52元1个月、149.00元半年

阿里云4核16G服务器优惠价格26.52元1个月、79.56元3个月、149.00元半年,配置为阿里云服务器ECS经济型e实例ecs.e-c1m4.xlarge,4核16G、按固定带宽 10Mbs、100GB ESSD Entry系统盘,活动链接 aliyunfuwuqi.com/go/aliyun 活动链接打开如下图&a…

(一)基于IDEA的JAVA基础5

Scanner的使用 使用scanner可以接收键盘上输入的数据, Scanner inputnew Scanner(System.in); 导包的方式: 什么是导包,导入的是jdk提供的java开发工具包,我们建一个java文件,psvm快捷输入后,打上new S…

有没有适合pr剪辑视频使用的蓝色魔法火焰能量特效素材模板

12个蓝色魔法火焰能量特效VFX元素pr素材模板。 可定制的能量电荷、灰尘等离子体和发光的电火花是游戏电影、电影特效或有影响力的视频内容的理想选择,增添了史诗般的电影质量。无论是神秘的爆炸、闪闪发光的闪电还是旋转的漩涡,每一部动画都是力量的灯塔…

力扣 柱形图中最大的矩形 单调栈

84. 柱状图中最大的矩形 - 力扣&#xff08;LeetCode&#xff09; 这篇文章讲的非常棒 class Solution { public:int largestRectangleArea(vector<int>& heights) {int n1heights.size(),ans0,i;新建数组&#xff0c;长度是heights.size()2第一位和最后一位为0 …

四种最新算法(小龙虾优化算法COA、螳螂搜索算法MSA、红尾鹰算法RTH、霸王龙优化算法TROA)求解机器人路径规划(提供MATLAB代码)

一、机器人路径规划介绍 移动机器人&#xff08;Mobile robot&#xff0c;MR&#xff09;的路径规划是 移动机器人研究的重要分支之&#xff0c;是对其进行控制的基础。根据环境信息的已知程度不同&#xff0c;路径规划分为基于环境信息已知的全局路径规划和基于环境信息未知或…

如果用java使用es

添加依赖 如何连接es客户端 RestHighLevelClient 代表是高级客户端 其中hostname&#xff1a;es的服务器地址&#xff0c;prot端口号 &#xff0c;scheme&#xff1a;http还是https 如果不在使用es可以进行关闭&#xff0c;可以防止浪费一些资源 java如何创建索引&#xff1…

Python PyQt5

实现界面开发&#xff0c;与tkinter功能一致&#xff0c;网上已有详细资料&#xff0c;此处仅记录自己的代码&#xff1a; 文章目录 1. 实操1.1 main.py1.2. 窗体模块代码1.3. 页面效果 2. 参考资料2.1. PyQt5 参考资料2.2. tkinter 参考资料 3. 安装注意事项3.1. 下载3.2 Pyc…

双碳目标下基于“遥感+”融合技术在碳储量、碳收支、碳循环等多领域监测与模拟

原文链接&#xff1a;双碳目标下基于“遥感”融合技术在碳储量、碳收支、碳循环等多领域监测与模拟https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247598506&idx6&snde95898e0b6017271a3b0bfbacc1f034&chksmfa82004dcdf5895bf44730ef2e6a5e8ee590cca1a…

Windows server 2012 R2系统怎么显示桌面图标

当我们在使用Windows server2012 R2服务器计算机时&#xff0c;为了方便&#xff0c;我们可以添加桌面图标。下面就给大家分享一下添加桌面图标的方法&#xff1b; 操作步骤如下&#xff1a; 1、第一步&#xff0c;我们打开server服务器&#xff0c;就可以看到如下画面&#x…

【python】python种子数据集——聚类分析建模(源码+数据集)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

如何做接口测试?

今天来聊聊接口测试&#xff0c;现在是2024年了&#xff0c;打开招聘网站随便点开一个招聘帖子&#xff0c;几乎都可以看到岗位JD要求写着有接口测试经验优先。其重要性可见一斑&#xff01; 目前&#xff0c;凡是好一点稍具规模的公司哪怕是大厂外包也几乎都要求会接口测试&a…

深度学习入门指南:从理论到实践

深度学习如何入门 深度学习是机器学习的一个分支&#xff0c;它通过模拟人脑神经网络的结构和功能来实现对数据的学习和理解。近年来&#xff0c;深度学习在图像识别、自然语言处理、语音识别等领域取得了显著的成果&#xff0c;越来越受到人们的关注。如果你想入门深度学习&a…

【LLAVA】Llava中在数据集制作过程中是怎么从CC3M中过滤出595K数据的?为什么这样做?

原文&#xff1a;CC3M. We extract noun-phrases using Spacy for each caption over the whole cc3m dataset, and count the frequency of each unique noun-phrase. We skip noun-phrases whose frequency is smaller than 3, as they are usually rare combinations concep…

[MySQL实战] 如何定义唯一约束(唯一索引)

文章目录 一、什么是唯一约束二、如何定义唯一约束2.1、建表时定义唯一约束--方法12.2、建表时定义唯一约束--方法22.3、为已创建的表定义唯一约束 三、删除唯一约束四、问题4.1、问题1&#xff1a;如何为多个列定义唯一约束&#xff1f; 五、总结 一、什么是唯一约束 唯一约束…

速通Markdown基础写法(含安装Typora)

什么是Markdown Markdown是一种轻量级标记语言&#xff0c;它允许人们使用易读易写的纯文本格式来编写文档&#xff0c;然后转换成格式丰富的HTML页面。这种语言吸收了很多在电子邮件中已有的纯文本标记的特性。 Markdown的语法简洁明了、学习容易&#xff0c;而且功能比纯文…

(2024,Mamba,DiT,之字扫描与空间连续性)ZigMa:之字形 Mamba 扩散模型

ZigMa: Zigzag Mamba Diffusion Model 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 1. 简介 2. 相关工作 3. 方法 3.1 背景&#xff1a;状态空间模型 3.2 扩散主干&…

Springboot开发中可能遇到的问题

SpringBoot特征&#xff1a; 1. SpringBoot Starter&#xff1a;他将常用的依赖分组进行了整合&#xff0c;将其合并到一个依赖中&#xff0c;这样就可以一次性添加到项目的Maven或Gradle构建中。 2,使编码变得简单&#xff0c;SpringBoot采用 JavaConfig的方式对Spring进行配置…

全网最靠谱的短网址平台,你知道几个?

在当今互联网时代&#xff0c;短网址平台成为了人们分享链接的常用工具。它们不仅可以将冗长的网址压缩为简洁的短链接&#xff0c;还能提供更多的功能和优势。在众多的短网址平台中&#xff0c;有几个平台以其可靠性和出色的性能脱颖而出。今天&#xff0c;我们就来介绍几个全…

ssh介绍

1. 什么是SSH&#xff1f; SSH是一种网络协议&#xff0c;用于计算机之间的加密登录。最早的时候&#xff0c;互联网通信都是明文通信&#xff0c;一旦被截获&#xff0c;内容就暴露无疑。1995年&#xff0c;芬兰学者Tatu Ylonen设计了SSH协议&#xff0c;将登录信息全部加密&…