自定义类型-结构体

2023-11-12

注:本文为C语言初阶内容


目录

1.结构体

1.1结构体的基础知识、声明和自引用

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

1.3结构体内存对齐和修改默认对齐数

1.4结构体传参


1.结构体

1.1结构体的基础知识、声明、初始化和自引用

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

比如说我们要简单描述一个学生,他的信息可以有年龄,名字,性别等。这时候我们可以用如下结构体来描述:

struct stu
{
	int age;
	char name[10];
	char sex[5];
}stu1;stu2;//注意分号

 上面的代码其实也是结构体的声明,stu1,stu2表示变量列表,一般情况下可写可不写。其实结构体还有一种特殊的声明,即匿名结构体类型。我们来看下面这段代码

struct 
{
	int age;
	char name[10];
	char sex[5];
}stu1,stu2;

对比两段代码,发现相比第一段代码,第二段代码的struct后少了stu。这时候我们就无法重新定义一个新的结构体类型了,换言之,上面的结构体代码我们只能使用两次(stu1,stu2)。所以通常情况下不用匿名结构体类型。另外,类似于函数,结构体也可以自我引用。那么,结构体应该如何自引用呢?

下面我们来对比如下两段代码:

struct Node
{
    int date;
    struct Node next;
};

 再看这一段:

struct Node
{
    int date;
    struct Node *next;
};

         哪一种可行?答案是第二段。让我们假设第一段代码可行,那么sizeof(struct Node)的值是多少呢?事实上,这种写法是违法的,因为结构体包含结构体,被包含的结构体中还有结构体,无限循环,大小是无法确定的。我们反观第二段代码,运用了指针变量,而指针变量的大小是确定的,因此可以计算大小。所以第二段代码的自引用是成立的。

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

        现在我们定义一个结构体变量

struct stu
{
	char name[20];
	int age;
}stu1,stu2;


int main()
{
	struct stu data1;//定义一个结构体变量:struct stu是一个类型,data1是一个变量
	struct stu data2 = { "LiHua",18 };//此处将data2进行了初始化,按照结构体的类型,依次输入相应数据
	return 0;
}

 另外,我们也可以在定义结构体后立即进行初始化,相关代码如下

struct stu
{
	char name[20];
	int age;
}data = { "LiHua",18 };

        在定义完结构体变量后我们就可以进行赋值了

struct stu
{
	char name[20];
	int age;
}stu1, stu2;


int main()
{
	struct stu data2 = { "LiHua",18 };
	data2.age = 19;//进行赋值
	data2.name[20] = "zhangsan";进行赋值
	return 0;
}

1.3结构体内存对齐和修改默认对齐数

        现在我们掌握了一些结构体的基本使用方法,现在我们来探讨另一个问题:计算结构体的大小。

        想要计算结构体的大小,我们需要了解结构体内存对齐这么个知识点。我们不妨举一个例子。

struct stu
{
	int tele;
	char name;
	int age;
};

这段代码的大小是多少?4?9?(VS环境下)答案是12。怎么来的?

首先需要掌握结构体的对齐规则:
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8(这是上文强调VS环境下的原因)
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

我们来看看上面例题的各个对齐数

struct stu
{
	int tele;//int类型大小为4,比8小,所以对齐数是4
	char name;//char类型大小是1,比8小,所以对齐数是1
	int age;//int类型大小为4,比8小,所以对齐数是4
};

如图所示,int类型的对齐数为4,0是其倍数,占4个字节;char类型是1,4是其倍数,占1个字节,再看int类型,对齐数是4,但是5不是4 的倍数,于是浪费三个字节的空间,到8,8是4的倍数,占4个字节。可以看到,这个结构体总共占了12个字节。

 

 为什么存在内存对齐?

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

1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
定类型的数据,否则抛出硬件异常。
2. 性能原因:
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
总体来说:
结构体的内存对齐是拿空间来换取时间的做法。
那在设计结构体的时候,我们既要满足对齐,又要节省空间, 

        那么默认对齐数可以修改吗?答案是肯定的。这例要用到 #pragma 这个预处理指令

#pragma pack(8)//设置默认对齐数为8
struct S1
{
    int name;
    int age;
    int id;
};
#pragma pack()//取消设置的默认对齐数,还原为默认

1.4结构体传参

 和其他类型一样,结构题传参也分为传值调用和传址调用,传值调用的函数,函数只能改变结构体变量的临时拷贝,而传址调用则可以改变结构体变量本身。简单举一个例子:

struct stu
{
	int tele;
	char name;
	int age;
};

void print1(struct stu stu1)//传值调用
{
	stu1.tele = 54321;
}

void print2(struct stu* stu1)//传址调用
{
	stu1->tele = 54321;
}

int main()
{
	//printf("%d", sizeof(struct stu));
	struct stu stu1 = { 12345,"LiHua",18 };
	print1(stu1);
	printf("%d\n", stu1.tele);
	print2(&stu1);
	printf("%d\n",stu1.tele);
	return 0;
}

输出结果:显然只有传址调用改变了结构体变量。

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自定义类型-结构体 的相关文章

  • UTF8/UTF16 和 Base64 在编码方面有什么区别

    In c 我们可以使用下面的类来进行编码 System Text Encoding UTF8 System Text Encoding UTF16 System Text Encoding ASCII 为什么没有System Text En
  • 部署 MVC4 项目时出错:找不到文件或程序集

    过去 我只需使用 Visual Studio 2012 发布到 AWS 菜单项即可部署我的 MVC4 网站 到 AWS Elastic Beanstalk 现在 程序可以在本地编译并运行 但无法部署 从消息来看 它似乎正在寻找不在当前部署的
  • 属性对象什么时候创建?

    由于属性实际上只是附加到程序集的元数据 这是否意味着属性对象仅根据请求创建 例如当您调用 GetCustomAttributes 时 或者它们是在创建对象时创建的 或者 前两个的组合 在由于 CLR 的属性扫描而创建对象时创建 从 CLR
  • 如何在没有 Control.Invoke() 的情况下从后台线程修改控件属性

    最近 我们遇到了一些旧版 WinForms 应用程序 我们需要更新一些新功能 在专家测试该应用程序时 发现一些旧功能被破坏 无效的跨线程操作 现在 在您认为我是新手之前 我确实有一些 Windows 窗体应用程序的经验 我不是专家 但我认为
  • fgets() 和 Ctrl+D,三次才能结束?

    I don t understand why I need press Ctrl D for three times to send the EOF In addition if I press Enter then it only too
  • 如何针对 Nancy 中的 Active Directory 进行身份验证?

    这是一篇过时的文章 但是http msdn microsoft com en us library ff650308 aspx paght000026 step3 http msdn microsoft com en us library
  • 使用 Google Analytics API 在 C# 中显示信息

    我一整天都在寻找一个好的解决方案 但谷歌发展得太快了 我找不到有效的解决方案 我想做的是 我有一个 Web 应用程序 它有一个管理部分 用户需要登录才能查看信息 在本节中 我想显示来自 GA 的一些数据 例如某些特定网址的综合浏览量 因为我
  • 为什么模板不能位于外部“C”块内?

    这是一个后续问题一个答案 https stackoverflow com questions 4866433 is it possible to typedef a pointer to extern c function type wit
  • 在 ASP.Net Core 2.0 中导出到 Excel

    我曾经使用下面的代码在 ASP NET MVC 中将数据导出到 Excel Response AppendHeader content disposition attachment filename ExportedHtml xls Res
  • 使用向量的 merge_sort 在少于 9 个输入的情况下效果很好

    不知何故 我使用向量实现了合并排序 问题是 它可以在少于 9 个输入的情况下正常工作 但在有 9 个或更多输入的情况下 它会执行一些我不明白的操作 如下所示 Input 5 4 3 2 1 6 5 4 3 2 1 9 8 7 6 5 4 3
  • 编译的表达式树会泄漏吗?

    根据我的理解 JIT 代码在程序运行时永远不会从内存中释放 这是否意味着重复调用 Compile 表达式树上会泄漏内存吗 这意味着仅在静态构造函数中编译表达式树或以其他方式缓存它们 这可能不那么简单 正确的 他们可能是GCed Lambda
  • 如何在 Team Foundation 上强制发表有意义的签入评论?

    我有一个开发团队有一个坏习惯 他们写道poor签入评论 当我们必须在团队基础上查看文件的历史记录时 这使得它成为一场噩梦 我已经启用了变更集评论政策 这样他们甚至可以在签到时留下评论 否则他们不会 我们就团队的工作质量进行了一些讨论 他们很
  • 可空属性与可空局部变量

    我对以下行为感到困惑Nullable types class TestClass public int value 0 TestClass test new TestClass Now Nullable GetUnderlyingType
  • AccessViolationException 未处理

    我正在尝试使用史蒂夫 桑德森的博客文章 http blog stevensanderson com 2010 01 28 editing a variable length list aspnet mvc 2 style 为了在我的 ASP
  • 检查 url 是否指向文件或页面

    我们需要以下内容 如果文件确实是文件 则从 URL 下载该文件 否则 如果它是一个页面 则什么也不做 举个简单的例子 我有以下命令来下载文件 My Computer Network DownloadFile http www wired c
  • char指针或char变量的默认值是什么[重复]

    这个问题在这里已经有答案了 下面是我尝试打印 char 变量和指针的默认值 值的代码 但无法在控制台上看到它 它是否有默认值或只是无法读取 ASCII 范围 include
  • 方法参数内的变量赋值

    我刚刚发现 通过发现错误 你可以这样做 string s 3 int i int TryParse s hello out i returns false 使用赋值的返回值是否合法 Obviously i is but is this th
  • 窗体最大化时自动缩放子控件

    有没有办法在最大化屏幕或更改分辨率时使 Windows 窗体上的所有内容自动缩放 我发现手动缩放它是正确的 但是当切换分辨率时我每次都必须更改它 this AutoScaleDimensions new System Drawing Siz
  • 如何使用 ReactiveList 以便在添加新项目时更新 UI

    我正在创建一个带有列表的 Xamarin Forms 应用程序 itemSource 是一个reactiveList 但是 向列表添加新项目不会更新 UI 这样做的正确方法是什么 列表定义 listView new ListView var
  • C++ 成员函数中的“if (!this)”有多糟糕?

    如果我遇到旧代码if this return 在应用程序中 这种风险有多严重 它是一个危险的定时炸弹 需要立即在应用程序范围内进行搜索和销毁工作 还是更像是一种可以悄悄留在原处的代码气味 我不打算writing当然 执行此操作的代码 相反

随机推荐

  • STM32——I2C通信理论基础(1)(学习笔记)

    STM32 I2C通信理论基础 硬件层 协议层 1 I2C基本读写过程 2 I2C通信的起始和停止信号 3 数据的有效性 4 响应 前言 我们在学习stm32的时候 要想学得更好 i2c协议的学习是必不可少的 现在很多的硬件 传感器等都是用
  • Vite2.0常见配置

    一 创建 1 创建 npm init vite latest my vue app template vue ts 查看 create vite 以获取每个模板的更多细节 vanilla vanilla ts vue vue ts reac
  • Win10-部署java环境教程

    一提到部署环境 不得不提到java环境 现如今java遍地走 python多如狗的世界里 如果不能在本地搭建一套java环境 都不好意思说自己是搞软件的 这里呢 给大家来分享一下 如何在一个新的机器上部署java环境 首先 java环境的配
  • FPGA零基础学习之Vivado-锁相环使用教程

    FPGA零基础学习之Vivado 锁相环使用教程 本系列将带来FPGA的系统性学习 从最基本的数字电路基础开始 最详细操作步骤 最直白的言语描述 手把手的 傻瓜式 讲解 让电子 信息 通信类专业学生 初入职场小白及打算进阶提升的职业开发者都
  • mybaties总结

    1 需要导入四个坐标 分别是mybatits junit log4j mysql connection java 2 连接数据库信息 配置mapper的位置 3 映射文件namespace对应的是接口全名 id是接口里面的方法名 resul
  • BUCK电路原理及PCB布局与布线注意事项

    1 BUCK架构 Buck架构 当开关闭合的时候 当开关断开的时候 根据伏秒平衡定理可得 Vin Vout DT Vout 1 D T gt Vin Vout D lt 1 在实际DCDC应用中 当Q1闭合的时候 在图1 a中 红线示出了当
  • Java面试——缓存

    一 什么是缓存 1 缓存就是数据交换的缓冲区 称作 Cache 当某一硬件要读取数据时 会首先从缓存汇总查询数据 有则直接执行 不存在时从内存中获取 由于缓存的数据比内存快的多 所以缓存的作用就是帮助硬件更快的运行 2 缓存往往使用的是RA
  • MMRotate:旋转框检测实现过程

    MMRotate 旋转框检测实现过程 MMRotate地址 https github com open mmlab mmrotate 文档地址 https mmrotate readthedocs io en latest 一 环境搭建 1
  • Raspberry Pi Zero 单板配置手记(四)调整 TF 卡分区大小的不同方式

    RPi Zero 调整 TF 卡分区大小的不同方式 本文章为系列文章 Raspberry Pi Zero 单板配置手记 的第四篇 上一篇为 Raspberry Pi Zero 单板配置手记 三 使用 NetworkManager 管理网络连
  • 启动httpd服务:SSLCertificateFile: file ‘/var/www/miq/vmdb/certs/server.cer‘ does not exist or is empty

    启动httpd服务 SSLCertificateFile file var www miq vmdb certs server cer does not exist or is empty 启动httpd服务 失败 复制代码 root te
  • UE5《Electric Dreams》项目PCG技术解析 之 理解Assembly(以SplineExample为例)

    文章目录 1 什么是Assembly 2 PCG部分 2 1 Assembly变换 2 2 Point变换 2 2 1 SG CopyPointsWithHierachy 2 2 2 过滤及点变换 2 2 3 ApplyHierachy 3
  • python 获取控制台输出内容 解决中文乱码

    Python获取控制台输出 1 使用subprocess库 非实时读取 import subprocess xe subprocess run iperf3 c 127 0 0 1 p 5668 J stdout subprocess PI
  • shell实现嵌入式软件看门狗

    shell实现嵌入式软件看门狗 长时间运行的嵌入式程序 有时会因为莫名其妙的原因挂掉 这时就需要有其他的程序来一直监控我们的程序 由于监控程序属于软件层面 因此这种程序被称为 软件看门狗 这里用一个shell脚本实现该功能 这个脚本会一直监
  • Nginx Lua 实战

    在 nginx conf 中配置 在 http 节点中配置 location staticitem get default type text html content by lua file lua staticitem lua 创建 s
  • vue中axios的参数位置整理

    每次在进行前后端联调的时候 总是因为参数放不对而影响进度 我人都麻了 真的记不住 还是整理一下以便后续开发 一 vue2和vue3的接口请求头 vue 2 const res await this axios get vue 3 const
  • 数据结构课程设计——客运订票系统

    目录 2需求分析 2 1系统功能 3总体设计 3 1功能模块图 4详细设计 4 1 详细的设计思路 车次设置 订票模块的功能 退票模块的功能 管理员模块的功能 4 2 算法流程图 5编码 5 1数据结构定义 1 乘客信息 2 候补队列乘客信
  • JAVA代码审计从入门到精通2-JAVA WEB动态调试

    动态调试 在代码开发和代码分析的过程中需要对代码进行动态调试 动态调试是指利用集成环境 IDE 自带的调试器跟踪软件运行 协助解决和分析软件的bug 动态调试需要对程序设置断点 通过对程序的某行代码设置断点 当程序运行到此代码处会自动停止
  • Qt:自定义信号变量类型

    1 定义变量类型 struct User STRUCT 预测结果 2 在定义后面添加声明 告知所有用到该信号变量的对象 建议1 2 3 放在一个头文件 供所有类包含 Q DECLARE METATYPE User STRUCT 3 incl
  • ajax实验,基于Ajax技术的实验管理系统

    摘要 本文的研究来源于常州纺织服装职业技术学院实验教学管理系统 是常州纺织服装职业技术学院教务管理系统的子系统 该系统主要完成制定实验教学计划 网上选课 三方互动 在深入研究Ajax技术原理和工作流程的基础上 提出一个基于Ajax技术的实验
  • 自定义类型-结构体

    注 本文为C语言初阶内容 目录 1 结构体 1 1结构体的基础知识 声明和自引用 1 2结构体变量的定义和初始化 1 3结构体内存对齐和修改默认对齐数 1 4结构体传参 1 结构体 1 1结构体的基础知识 声明 初始化和自引用 结构体是一些