C语言结构体介绍(超详细)

news2024/11/24 20:54:49

文章目录

  • 每日一言
  • 结构体是什么?
  • 为什么要使用结构体?
  • 如何使用结构体?
    • 结构体的定义
    • 结构体的声明
    • 如何访问结构体中的成员
  • 结构体内存对齐
    • 什么是结构体内存对齐
      • 对齐规则
        • 修改默认对齐数
    • 为什么存在结构对齐
  • 总结
  • 结语

每日一言

Develop your imagination – you can use it to create in your mind what you hope to create in your life.
发展你的想像力 – 你可以用它在心里创造你想在现实生活创造的东西。


结构体是什么?

结构体是一种自定义的数据类型,可以包含多个不同类型的数据成员,并可以根据这些成员进行组合和访问。结构体可以用于表示一个具有多个属性的实体或对象,例如一个人的姓名、年龄和性别,一个车辆的品牌、型号和颜色,等等。

为什么要使用结构体?

C语言已经为我们提供了许多的内置类型,如:int、long、float、double、char、short等,但这些类型只能描述相对单一的事物。
假如我要描述一个人,人是一个相对复杂的事物,他有姓名、年龄、性别、身份证号、体重、电话号码等属性。这时如果只用上面给出的类型是很难描述一个人的所有信息的。

如何使用结构体?

结构体的定义

struct 结构体名称 {
    数据类型 变量名1;
    数据类型 变量名2;
    // ...
};

例如用结构体描述一个人:

struct Person {
    char name[20];//名字
    int age;//年龄
    char gender;//性别
    char id_card[18];//身份证号
    float weight;//体重
    char phone[11];//电话
};

结构体的声明

声明结构体变量的格式如下:

struct 结构体名 变量名;

例如,声明一个名为awa,年龄为18岁,性别为男,身份证号为666666,体重为60.2,电话为1234567的人:

方式一
声明结构体变量时直接定义结构体

代码如下:

struct Person {
    char name[20];//名字
    int age;//年龄
    char gender;//性别
    char id_card[18];//身份证号
    float weight;//体重
    char phone[11];//电话
}awa = {"awa",18,'M',"666666",60.2,"1234567"};

方式二
先定义结构体类型,再声明结构体变量

代码如下:

struct Person {
    char name[20];//名字
    int age;//年龄
    char gender;//性别
    char id_card[18];//身份证号
    float weight;//体重
    char phone[11];//电话
};

struct Person awa = {"awa",18,'M',"666666",60.2,"1234567"};

两种方式的本质区别在于第一种方式在定义结构体变量的同时也定义了结构体类型,而第二种方式分别定义了结构体类型和结构体变量。而在实际应用中,通常会使用第一种方式,代码会更加简洁明了。 C语言也支持在结构体中嵌套定义其他结构体。

如何访问结构体中的成员

我们依然以上面的awa为例,如何在屏幕上打印出awa的电话呢?
我们有两种方法:

法一:
通过点操作符来访问结构体成员。

代码如下:

printf("awa的电话是:%s\n", awa.phone);

法二:
通过指针操作符来访问结构体成员。

代码如下:

struct Person *p;//定义一个指针p,它的类型是struct Person。
p = &awa;//将p指向结构体变量awa的地址。
printf("awa的电话是:%s\n", p->phone);

结构体内存对齐

现在我们对结构体有了大致的了解,接下来我们来谈一谈结构体是如何在内存中存储的。只有了解了它的本质,我们用起来就更加得心应手。

什么是结构体内存对齐

内存对齐是指将数据存储在内存中时,按照某种规则对其进行填充,使其在访问时的速度更快。这主要是因为CPU的读取速度与地址对齐有关。

对齐规则

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

例:
求AA_t 所站的字节大小(假如编译器默认对齐数为8字节)

typedef struct{
  int a;
  char b;
  short c;
  short d;
}AA_t;

计算过程:
在这里插入图片描述

注意:
VS中默认的对齐数为8
Linux中gcc没有默认对齐数,对齐数就是成员自身的大小

修改默认对齐数

#pragma 这个预处理指令可以改变编译器的默认对齐数

例:
#pragma pack(1)
设置默认对齐数为1

#pragma pack()
取消设置的默认对齐数

一般不建议修改默认对齐数,它会导致许多问题。

1.可能会破坏结构体的内存对齐,导致结构体成员的访问速度变慢,因为不是按照CPU的最佳对齐方式进行的。

2.可能会增加内存的浪费。如果对齐数太小,内存对齐不足,会导致内存浪费,因为需要加入一些填充字节来填充对齐差距。

3.可能会影响平台的可移植性。不同的平台对内存对齐的要求可能不同,因此在不同的平台上运行代码时可能会出现错误或不一致的结果。

4.可能会使代码变得难以维护,并且会增加调试难度。更改默认对齐数通常是非标准的做法,开发人员可能需要花费更多时间来解决由此引起的问题。

为什么存在结构对齐

通过对结构体进行对齐,可以保证每个结构体成员访问时都能够在一个内存块中连续访问,提高了代码的执行效率。同时,结构体对齐也能够减少内存碎片的产生,进一步提高内存的利用效率。

注意:
内存对齐可以提高数据访问的效率,但同时也会增加内存空间的浪费。因此,在设计结构体时,需要权衡对齐对空间利用率和访问效率的影响,以达到最优的设计。
通常我们尽量让占用空间小的成员集中在一起

总结

  1. 结构体的定义:需要使用关键字struct,语法格式如下:
struct 结构体名称 {
    数据类型 变量名1;
    数据类型 变量名2;
    // ...
};
  1. 成员变量的定义:可以是基本数据类型、指针类型、数组类型等。定义时需要指明变量名和数据类型。

  2. 结构体的大小:结构体的大小是所有成员变量大小的累加,需要考虑对齐方式和填充字节。

  3. 结构体的初始化:可以采用两种方式进行初始化,一种是在定义时赋值,另一种是通过赋值运算符对结构体对象进行初始化。

  4. 结构体的成员访问:可以通过".“或”->“运算符进行成员访问,”.“用于访问结构体对象的成员,”->"用于访问指向结构体的指针的成员。

  5. 结构体的传参:可以将结构体作为函数参数传递,可以通过传值或传指针的方式进行传参。

  6. 结构体的对齐方式:需要指明对齐方式,可以通过#pragma pack指令或__attribute__((packed))关键字来进行设置。


结语

请给自己些耐心,一口吃不成胖子。
山外青山楼外楼,莫把百尺当尽头。
保持空杯心态加油努力吧!


都看到这里啦!真棒(*^▽^*)

可以给作者一个免费的赞赞吗,这将会鼓励我继续创作,谢谢大家

编程小白写作,如有纰漏或错误,欢迎指正


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

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

相关文章

Ubuntu系统下使用apt-get安装Redis

记录一下Ubuntu20.04 64位系统下使用apt-get安装Redis 首先检查一下系统是否安装过redis whereis redismywmyw-K84HR:~$ whereis redis redis: mywmyw-K84HR:~$ 更新软件包 sudo apt-get update -y安装redis sudo apt-get install redis-server -ymywmyw-K84HR:~$ sudo apt…

【S32K3环境搭建】-0.1-安装S32 Design Studio for S32 Platform 3.5

目录(S32DS安装步骤详细) 1 安装S32 Design Studio for S32 Platform 3.5准备工作 2 下载S32 Design Studio for S32 Platform 3.5安装包 2.1 获取S32DS的License许可 3 安装S32 Design Studio for S32 Platform 3.5 4 打开S32 Design Studio for S…

DNS协议(DNS规范、DNS报文、DNS智能选路)

目录 DNS协议基本概念 DNS相关规范 DNS服务器的记录 DNS报文 DNS域名查询的两种方式 DNS工作过程 DNS智能选路 DNS协议基本概念 DNS的背景 我们知道主机通信需要依靠IP地址,但是每次通过输入对方的IP地址和对端通信不够方便,IP地址不好记忆 因此提…

备战春招——12.05算法

树、二叉树 本次主要是对树、二叉树的前中后和递归与非递归遍历以及通过这种结构完成一些操作实现。 二叉树 中序遍历 中序遍历就是中间打印出结果嘛,如下列递归实现的,中间取结果. /** 递归实现* Definition for a binary tree node.* struct TreeNode {* …

axios使用

Get请求 Post请求 出问题了: 并发请求 全局配置 多个实例如何处理 拦截器 axios在Vue中的模块封装

Pyside2 (Qt For Python)进度条功能实现

Pyside2 (Qt For Python)进度条功能实现 进度条(QProgressBar) 今天来介绍PySide2进度条(QProgressBar)的使用,如下所示: 说明 进度条也是一个常用的控件,当程序需要做一件比较耗费时间的任…

【PduR路由】PduR模块详细介绍

目录 1.PDUR模块功能介绍 2.关键概念理解 3.功能详细设计 3.1I-PDU handling 3.1.1 I-PDU Reception to upper module(s) 3.1.1.1 Communication Interface 3.1.1.2 Transport Protocol 3.1.2 I-PDU Transmission from upper module(s) 3.1.2.1 Multicast 3.1.2.2 Co…

流媒体音视频/安防视频云平台/可视化监控平台EasyCVR无法启动且打印panic报错,是什么原因?

国标GB视频监控管理平台/视频集中存储/云存储EasyCVR能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,实现视频资源的鉴权管理、按需调阅、全网分发、智能分析等。AI智能大数据视频分析EasyCVR平台已经广泛应用在工地、工厂、园…

软件设计模式之组合模式

组合模式:将对象组合成树形结构。 案例:公司管理。一个公司可以分总公司和分公司,无论是总公司还是分公司都有自己的部门,如人力资源管理部门、财务部门。分公司可以建立自己在不同地域的办事处。请使用组合模式打印出某个公司的…

Nodejs+vue+ElementUi自动排课系统

使用自动排课系统分为管理员和学生、教师三个角色的权限子模块。 管理员所能使用的功能主要有:首页、个人中心、学生管理、教师管理、班级信息管理、专业信息管理、教室信息管理、课程信息管理、排课信息管理、系统管理等。 学生可以实现首页、个人中心、排课信息管…

Linux系统调试课:PCIe调试手段

文章目录 一、lspci 命令二、pciutils 工具沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本文我们要介绍pcie调试手段。 一、lspci 命令 通过lspci可以查看当前系统挂载了哪些pci设备。 lspci - 列出 PCI 设备 lspci 命令可以列出计算机中所有 PCI 设备的详细信息,…

Leetcode每日一题学习训练——Python3版(到达首都的最少油耗)

版本说明 当前版本号[20231205]。 版本修改说明20231205初版 目录 文章目录 版本说明目录到达首都的最少油耗理解题目代码思路参考代码 原题可以点击此 2477. 到达首都的最少油耗 前去练习。 到达首都的最少油耗 ​ 给你一棵 n 个节点的树(一个无向、连通、无环…

处理k8s中创建ingress失败

创建ingress: 如果在创建过程中出错了: 处理方法就是: kubectl get ValidatingWebhookConfiguration kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission 然后再次创建,发现可以:

阿里云环境下的配置DNS和SLB的几种实践示例

一、背景 对于大多中小型公司来说,生产环境大多是购买阿里云或者腾讯云等等,也就存在以下需求: 外网域名内网域名SLB容器化部署 特别是前两项,一定是跳不过的。容器化部署,现在非K8S莫属了。 既然是购买阿里云&…

初级数据结构(一)——顺序表

文中代码源文件已上传:数据结构源码 1、顺序表的特点 1.1、数组 现实中数据记录一般都记录在表格中,如进货单、菜单等,它们的最大特点就是有序。表述中可以用第一项、第二项、第 n 项来描述表格中某个数据或者某串数据。在 C 语言中&#…

解决ssr服务端渲染程序启动报错: ReferenceError: location is not defined

现象: 原因:chatgpt给出的解释很到位: 该错误表明代码尝试访问 location 对象,该对象通常在浏览器环境中可用。 然而,你的服务器端代码正在 Node.js 环境中运行,而在这个环境中 location 对象未定义。 问…

Kafka 生产者 API 指南:深入理解生产者的实现与最佳实践

Kafka 是一个高性能、分布式的消息中间件系统,而其生产者 API 是连接应用程序与 Kafka 集群之间的纽带。本篇博客将深入探讨 Kafka 生产者 API 的核心概念、用法,以及一些最佳实践,帮助你更好地利用 Kafka 构建可靠的消息生产系统。 1. Kafk…

uniapp得app云打包问题

获取appid,具体可以查看详情 也可以配置图标,获取直接生成即可 发行 打包配置 自有证书测试使用时候不需要使用 编译打包 最后找到安装包apk安装到手机 打包前,图片命名使用要非中文,否则无法打包成功会报错

Kafka中的Topic

在Kafka中,Topic是消息的逻辑容器,用于组织和分类消息。本文将深入探讨Kafka Topic的各个方面,包括创建、配置、生产者和消费者,以及一些实际应用中的示例代码。 1. 介绍 在Kafka中,Topic是消息的逻辑通道&#xff0…

SpringBoot集成mail发送邮件

前言 发送邮件功能,借鉴 刚果商城,根据文档及项目代码实现。整理总结便有了此文,文章有不对的点,请联系博主指出,请多多点赞收藏,您的支持是我最大的动力~ 发送邮件功能主要借助 mail、freemarker以及rocke…