自定义类型-结构体

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(使用前将#替换为@)

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

随机推荐

  • 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结构体的基础知识 声明 初始化和自引用 结构体是一些