C语言自定义类型结构体

news2024/11/13 7:56:56

 

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取地址存数值,存的数值可能会被截取,就不是想要的数据。

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

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

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

相关文章

普发Pfeiffer分子泵TPH2101PUP/PCCT安装使用维护说明

普发Pfeiffer分子泵TPH2101PUP/PCCT安装使用维护说明

代码随想录算法训练营第31天| 455.分发饼干、376. 摆动序列、53. 最大子序和

455.分发饼干 题目链接:分发饼干 题目描述:假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最…

FloodFill算法——图像渲染

文章目录 题目解析题目内容解读 算法解析代码解析 题目解析 首先我们先来看看题目:图像渲染 题目内容解读 我们来解读一下题目内容这个题目的意思其实就是有一个如下图所示的二维矩阵 这个题目的意思在这类题目中也是非常标准的,就是给我们一个二维数…

docker的部署与安装以及部署一个docker(容器)应用及docker容器常出现的问题

docker 架构图 一、docker的部署与安装 1、在 CentOS 上安装 Docker 移除旧版本(如果有的话):sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-…

用vscode调试cpp程序相关操作记录

需要在服务器上用vscode调试cpp程序,写此记录launch.json配置和相关步骤错误导致的问题 1.在需要运行程序的服务器上安装C/C Extension Pack(之前只在本地装了),可以支持调试C/C应用程序(设置断点,单步执行&#xff0c…

爱帮供应链邀您参观2024杭州快递物流供应链与技术装备展览会

2024年7月8-10日 | 杭州国际博览中心 同期举办:2024中国数字物流技术与应用展 2024国际电商物流包装产业展 2024新能源商用车、物流车展 展会介绍 本届展会致力于全面展示快递物流上下游领域的创新解决方案,涵盖快递物流供应链、智能装备、AGV机器人…

正信晟锦:多年不联系的好友借钱怎么办

多年不见的老友突然出现,带着迫切的求助信息——借钱。面对这样的请求,我们该如何应对? 当一个多年未联络的朋友突然出现请求借款时,这确实是一个棘手的问题。一方面,我们可能对旧日友情存有怀念与不舍;另一方面,时间…

Windows10安装SSH

Linux运维工具-ywtool 目录 1. 打开设置2. 应用3.管理可选功能4.添加功能5.安装OpenSSH服务器6.测试是否安装成功 1. 打开设置 windows桌面按下"win l"键调出"设置"2. 应用 点击"应用"3.管理可选功能 点击"管理可选功能"4.添加功能…

【系统架构师】-计算机网络

1、网络的划分 网络性能指标:速率、带宽(频带宽度或传送线路速率)、吞吐量、时延、往返时间、利用率。 网络非性能指标:费用、质量、标准化、可靠性、可扩展性、可升级性、易管理性和可维护性。 总线型(利用率低、干扰大、价格低)、 星型(交换机转发形…

【笔记】以论文发表形式通俗理解 TCP/IP模型

【笔记】以论文发表形式通俗理解 TCP/IP模型 前言TCP/IP模型理论通俗理解 前言 在网络基础学习过程中,以前只对TCP/IP理解个字面,网上查一下能知道个字面意思,但是连起来到底是什么意思,还是一知半解的,停留在表面&am…

阿里云4核8G服务器多少钱一年?

阿里云4核8G服务器优惠价格955元一年,配置为ECS通用算力型u1实例(ecs.u1-c1m2.xlarge)4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选,CPU采用Intel(R) Xeon(R) Platinum处理器,阿里云活动链接 aliyunfuwuq…

document.documentElement.clientHeight与document.body.clientHeight的区别

网页可见区域高:document.body.clientHeight 网页正文全文高:document.body.scrollHeight clientHeight: 表示可视区域高度, 包括padding但不包括border、水平滚动条、margin的元素的高度 offsetHeight:表示可视区域高…

Jackson 2.x 系列【1】概述

有道无术,术尚可求,有术无道,止于术。 本系列Jackson 版本 2.17.0 源码地址:https://gitee.com/pearl-organization/study-seata-demo 文章目录 1. 前言2. 什么是 JSON3. 常用 Java JSON 库4. Jackson4.1 简介4.2 套件4.3 模块4.…

RIPGeo代码理解(五)utils.py( 辅助函数)第一部分

​ 代码链接:RIPGeo代码实现 ├── lib # 包含模型(model)实现文件 │ |── layers.py # 注意力机制的代码。 │ |── model.py # TrustGeo的核心源代码。 │ |── sublayers.py # layer.py的支持文件。 │ |── utils.p…

【MySQL】2.MySQL数据库的基本操作

目录 数据库基本操作 查看数据库信息 查看数据库结构 显示数据表的结构(字段) 常用的数据类型 数据库管理操作 SQL语句概述 SQL分类 1.DDL:数据定义语言 1.1创建数据库和表 创建数据库 创建数据表 1.2删除数据库和表 删除数据表…

2024年【化工自动化控制仪表】考试试卷及化工自动化控制仪表模拟考试题

题库来源:安全生产模拟考试一点通公众号小程序 化工自动化控制仪表考试试卷是安全生产模拟考试一点通总题库中生成的一套化工自动化控制仪表模拟考试题,安全生产模拟考试一点通上化工自动化控制仪表作业手机同步练习。2024年【化工自动化控制仪表】考试…

langchain+chatglm3+BGE+Faiss Linux环境安装依赖

前言 本篇默认读者已经看过之前windows版本,代码就不赘述,本次讲述是linux环境配置 超短代码实现!!基于langchainchatglm3BGEFaiss创建拥有自己知识库的大语言模型(准智能体)本人python版本3.11.0(windows环境篇&…

基于Gabor滤波器的指纹图像识别,Matlab实现

博主简介: 专注、专一于Matlab图像处理学习、交流,matlab图像代码代做/项目合作可以联系(QQ:3249726188) 个人主页:Matlab_ImagePro-CSDN博客 原则:代码均由本人编写完成,非中介,提供…

索尼下一代游戏主机PS5将于11月20日发售

索尼下一代游戏机PS5将于2020年11月20日发布。据悉,这款游戏机的售价可能会达到499美元(约合人民币3500元)。 我们知道游戏主机的价格低于游戏PC的价格。 既然PS5的主要硬件配置已经公开,那么现在配置一台同样配置的游戏PC需要多少…

从零开始学Spring Boot系列-集成Kafka

Kafka简介 Apache Kafka是一个开源的分布式流处理平台,由LinkedIn公司开发和维护,后来捐赠给了Apache软件基金会。Kafka主要用于构建实时数据管道和流应用。它类似于一个分布式、高吞吐量的发布-订阅消息系统,可以处理消费者网站的所有动作流…