C语言 - 结构体、结构体数组、结构体指针和结构体嵌套
结构体的意义
问题:学籍管理需要每个学生的下列数据:学号、姓名、性别、年龄、分数,请用 C 语言程序存储并处理一组学生的学籍。
单个学生学籍的数据结构:
- 学号(num): int 型
- 姓名(name) :char [ ] 型
- 性别(sex):char 型
- 年龄(age):int 型
- 分数(score):float 型
思考:如果有多个学生,该怎么定义,已学数据类型无法解决(已学的数据类型需要定义好多变量,不友好)。
概述
- 正式:
结构体是由一批数据组合而成的结构型数据。组成结构型数据的每个数据被称为结构型数据的 “成员” ,其描述了一块内存区间的大小及解释意义。 - 通俗:
结构体属于用户自定义的数据类型,允许用户存储不同的数据类型。
在C语言中,定义结构体的语法格式如下:
struct 结构体名 {类型 成员1;类型 成员2;// ...
};
其中,结构体名
是您自定义的结构体类型名称,可以根据需求进行命名。成员1
、成员2
等表示结构体的成员变量,每个成员都有自己的类型和名称。
定义结构体后,可以使用该结构体类型创建结构体变量,并访问结构体的成员。访问结构体成员的语法是使用结构体变量名后跟成员名,中间使用点.
进行连接。
结构体的使用:
-
struct 结构体名 变量名
-
struct 结构体名 变量名 = {成员1值,成员2值…}
-
定义结构体时顺便创建变量(这时候创建几个变量都可以,中间用逗号隔开,直接在创建的时候赋值也可以,例如:)
struct student {int num; //学号char name[16]; //姓名float score; //成绩 }stu5 = {1002,"lihua",89},stu6;
-
如果只想给一部分数据赋值的话:
struct 结构体名 变量名 = { .name = "cuiyi", .num = 111, };
下面是一个更完整的示例:
#include <stdio.h>// 定义一个结构体
struct Person {char name[50];int age;float height;
};int main() {// 创建一个结构体变量struct Person person1;// 访问结构体的成员strcpy(person1.name, "John");person1.age = 25;person1.height = 1.75;// 输出结构体的成员printf("Name: %s\n", person1.name);printf("Age: %d\n", person1.age);printf("Height: %.2f\n", person1.height);return 0;
}
在上述示例中,我们定义了一个名为Person
的结构体,它包含了姓名、年龄和身高三个成员变量。然后,我们创建了一个名为person1
的结构体变量,并给它的成员赋值。最后,使用printf
函数输出结构体的成员值。
结构体数组
- 作用:将自定义的结构体放入数组中方便维护
- 语法:
struct 结构体名 数组名[元素个数] = {{}, {}, …{}}
示例:
#include<stdio.h>struct stu
{char name[16];int age;float score;
}s[3];int main()
{struct stu s[3] = {{"zhangsan",18,500},{"lisi",18,530},{"wangwu",18,550}};int i;for (i = 0; i < 3; i++){printf("name=%s, age=%d, score=%f\n",s[i].name,s[i].age,s[i].score);}return 0;
}
结构体指针
- 作用:通过指针访问结构体的成员
- 语法:
struct 结构体名 *指针名;
- 利用操作符->可以通过结构体指针访问结构体属性(比如s.name 有一个指针 ps 指向 s ,那么可以用 ps->name 代替 s.name)
示例:
结构体数组和结构体指针
#include<stdio.h>struct stu
{char name[16];int age;float score;
}s[3];int main()
{struct stu s[3] = {{"zhangsan",18,500},{"lisi",18,530},{"wangwu",18,550}};struct stu *ps = s;//定义一个指针指向结构体数组int i;for (i = 0; i < 3; i++){printf("name=%s, age=%d, score=%f\n",(*(ps+i)).name,(*(ps+i)).age,(*(ps+i)).score);}return 0;
}
在上面的代码中,一定要记得 (*(ps+i)) 才是一个大括号里面的值,这样才能 .name .age .score 。
结构体嵌套结构体
- 含义
结构体中的成员可以是另一个结构体 - 语法
struct 结构体名
{struct 结构体名 成员名;
};
示例:
#include <stdio.h>
#include <string.h>struct person
{char name[16];int age;char sex;
};struct student
{struct person stu; float score;
};struct teacher
{struct person tea;char phone[12];
};int main(int argc, const char *argv[])
{struct student s;strcpy (s.stu.name,"zhangsan");s.stu.age = 12;s.stu.sex = 'm';s.score = 98;printf("name = %s,age = %d, sex = %c, score = %f\n", s.stu.name, s.stu.age, s.stu.sex, s.score);struct teacher t;struct teacher *p = &t;strcpy (p->tea.name, "lisi");p->tea.age = 54; //注意这里操作符 -> 的用法p->tea.sex = 'w';strcpy (p->phone, "13112341234");printf("name = %s,age = %d, sex = %c, score = %s\n", t.tea.name, t.tea.age, t.tea.sex, t.phone);return 0;
}
上述代码中,有一个部分用到了 p->tea.age 这种形式,这是因为p是指针,而 tea 只是一个普通变量,所以从 tea 出发不能用 ->,只有指针才可以使用这个操作符。
结构体大小
字节对齐
- 含义
字节对齐主要是针对结构体而言的,通常编译器会自动对其成员变量进行对齐,以提高数据存取的效率。(因为如果按照类型实际的大小来判断的话,那么需要判断很多次,这样对齐了以后有规律就不用判断了) - 作用
- 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
- 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
计算方法
- 自身对齐 (这个数据类型大小是多少就是多少)
- 默认对齐 (4字节)
- 有效对齐 (在自身对齐和默认对齐之间选最小)
规则:(地址 / 有效地址) 必须是整数。
计算过程:
- 把结构体里每个变量的类型的自身对齐,默认对齐和有效对齐分别写出来;
- 以有效对齐为准写每个变量的地址,最开始那个变量的地址肯定是0,然后后面叠加,注意在这个过程中要遵从**<规则>**,比如图中的变量 b ,本来地址应该是 1 ,但是因为 1 / 4 不是整数,所以要扩充到 4 凑整,那么这个时候 变量 a 的地址浪费了 1 2 3 这三个地址,又因为 b 本身就是 4 个字节,所以它的地址是 4 5 6 7。 c 和 d 因为都可以整除有效对齐,所以每个都加 1 个字节就行;
- 最终看一下,有效对齐最大的是 4 ,所以每个都要以 4字节 对齐,则要在变量 d 的后面再补 2 个地址:10 和 11 (因为前面的 8 和 9 已经占了 2 个地址了,还差 2 个地址凑够 4 个地址)。
- 得出结果:结构体 A 的地址是 0~11 ,所以大小是 12 。
上述过程要注意:能不能整除只能决定每个变量开头的地址,具体要每一行的地址从开头的地址要写到几要看变量类型的 sizeof 是多少。比如有 double c,c的开头地址是 8 ,那么这个变量占的字节就是 8 9 10 11 12 13 14 15 这八个字节。
相关文章:

C语言 - 结构体、结构体数组、结构体指针和结构体嵌套
结构体的意义 问题:学籍管理需要每个学生的下列数据:学号、姓名、性别、年龄、分数,请用 C 语言程序存储并处理一组学生的学籍。 单个学生学籍的数据结构: 学号(num): int 型姓名(…...
python安装playwright问题记录
python安装playwright这个时候,有得时候会https timeout 有的时候会 not found。 我最后使用的方法三,挺好用的。 PyPI The Python Package Index 可以尝试使用的方法 1. 更换pip源:使用国内的pip源可以提高下载速度并减少超时问题。例如,…...
关于gRPC微服务利弊之谈
gRPC微服务架构包括以下几个主要组件: 服务定义:定义服务的接口和消息格式,使用Protocol Buffers或其他的消息格式进行描述。服务实现:实现定义的服务接口和消息处理逻辑。服务器端实现:在服务器端,需要实…...

【Terraform学习】使用 Terraform创建Lambda函数启动EC2(Terraform-AWS最佳实战学习)
本站以分享各种运维经验和运维所需要的技能为主 《python》:python零基础入门学习 《shell》:shell学习 《terraform》持续更新中:terraform_Aws学习零基础入门到最佳实战 《k8》暂未更新 《docker学习》暂未更新 《ceph学习》ceph日常问题解…...

Mac软件删除方法?如何删除不会有残留
Mac电脑如果有太多无用的应用程序,很有可能会拖垮Mac系统的运行速度。因此,卸载电脑中无用的软件是优化Mac系统运行速度的最佳方式之一。Mac卸载应用程序的方式是和Windows有很大的区别,特别对于Mac新用户来说,如何无残留的卸载删…...
编程之道:【性能优化】提高软件效率的实际建议和避免常见陷阱
在今天的数字化世界中,软件性能是应用程序成功的关键之一。无论是网页加载速度、移动应用的响应时间还是后端服务器的处理速度,性能都直接影响着用户满意度。在追求高性能时,开发人员需要采取一系列实际建议,同时避免常见的陷阱。…...

VGG的结构:视觉几何组(Visual Geometry Group)
目录 1. VGG 的结构 2. VGG 的网络细节 3. VGG 的代码实现 1. VGG 的结构 牛津大学的视觉几何组(Visual Geometry Group)设计了 VGGNet(也称为 VGG),一种经典的卷积神经网络 (CNN) 架构。在 2014 年 ILSVRC 分类任务中,VGG 取…...
VBA:按照Excel工作表中的名称列自动汇总多个工作薄中对应sheet中所需要的数据
需求如下: B列为产品名为合并单元格,C列为供应商名,G、H列为金额数据;数据源放在同一个文件夹内,B列产品名来源于工作薄名称中间的字符串,C列供应商名来源于工作薄中的sheet名;G、H列金额数据来…...

Mybatis1.9 批量删除
1.9 批量删除 1.9.1 编写接口方法1.9.2 编写SQL语句1.9.3 编写测试方法 如上图所示,用户可以选择多条数据,然后点击上面的 删除 按钮,就会删除数据库中对应的多行数据。 1.9.1 编写接口方法 在 BrandMapper 接口中定义删除多行数据的方法。…...

CUDA小白 - NPP(2) -图像处理-算数和逻辑操作(2)
cuda小白 原始API链接 NPP GPU架构近些年也有不少的变化,具体的可以参考别的博主的介绍,都比较详细。还有一些cuda中的专有名词的含义,可以参考《详解CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid》 常见的NppStatus…...
python+redis实现布隆过滤器(含redis5.0版本以上和5.0以下版本的两份代码)
布隆过滤器是一种空间效率极高的概率数据结构,用于测试一个元素是否是集合的成员。如果布隆过滤器返回 False,则元素绝对不在集合中。如果返回 True,则元素可能在集合中,但也可能是一个误报。布隆过滤器利用了多个不同的哈希函数对…...
SpringBoot Thymeleaf iText7 生成 PDF(2023/08/29)
SpringBoot Thymeleaf iText7 生成 PDF(2023/08/29) 文章目录 SpringBoot Thymeleaf iText7 生成 PDF(2023/08/29)1. 前言2. 技术思路3. 实现过程4. 测试 1. 前言 近期在项目种遇到了实时生成复杂 PDF 的需求,经过一番…...

【核磁共振成像】并行采集MRI
目录 一、并行成像二、SENSE重建三、SMASH重建四、灵敏度校准五、AUTO-SMASH和VD-AUTO-SMASH六、GRAPPA重建七、SPACE RIP重建算法八、PILS重建算法九、PRUNO重建算法十、UNFOLD算法 一、并行成像 并行MR成像(pMRI):相位阵列接受线圈不但各有自己专用的接受通道,而且…...

深度图相关评测网站
文章目录 1 单目/Stereo相关测评网站介绍12 单目/Stereo相关测评网站介绍23 单目/Stereo相关测评网站介绍3 1 单目/Stereo相关测评网站介绍1 https://vision.middlebury.edu/stereo/eval3/ 2 单目/Stereo相关测评网站介绍2 http://www.cvlibs.net/datasets/kitti/eval_stereo…...

本地部署 CodeLlama 并在 VSCode 中使用 CodeLlama
本地部署 CodeLlama 并在 VSCode 中使用 CodeLlama 1. CodeLlama 是什么2. CodeLlama Github 地址3. 下载 CodeLlama 模型4. 部署 CodeLlama5. 在 VSCode 中使用 CodeLlama6. 使用WSGI启动服务7. 创建 start.sh 启动脚本 1. CodeLlama 是什么 Code Llama 是一个基于 Llama 2 的…...
Agilent33220A任意波形发生器
20MHz正弦波和方波脉冲、斜披、三角波,噪声和直流波形14-bit,50MSa/s,64K点任意波形AM、FM、PM、FSK和PWM凋制线性和对数扫描及脉冲串模式10mVpp至10Vpp幅苗范围图形化界面可以对信号设置进行可视化验证通过USB、GPIB和LAN连接 性能优异的各种函数的波形…...

springboot第37集:kafka,mqtt,Netty,nginx,CentOS,Webpack
image.png binzookeeper-server-start.shconfigzookeeper.properties.png image.png image.png 消费 image.png image.png image.png image.png image.png image.png image.png image.png image.png Netty的优点有很多: API使用简单,学习成本低。功能强大…...

NVIDIA DLI 深度学习基础 答案 领取证书
最后一节作业是水果分类的任务,一共6类,使用之前学习的知识在代码段上进行填空。 加载ImageNet预训练的基础模型 from tensorflow import kerasbase_model keras.applications.VGG16(weights"imagenet",input_shape(224, 224, 3),include_t…...
axios模拟表单提交
axios默认是application/json方式提交,controller接收的时候必须以RequestBody的方式接收,有时候不太方便。如果axios以application/x-www-form-urlencoded方式提交数据,controller接收的时候只要保证名字应对类型正确即可。 前端代码&#…...

智安网络|探索物联网架构:构建连接物体与数字世界的桥梁
物联网是指通过互联网将各种物理设备与传感器连接在一起,实现相互通信和数据交换的网络系统。物联网架构是实现这一连接的基础和框架,它允许物体与数字世界之间的互动和协作。 一、物联网架构的概述 物联网架构是一种分层结构,它将物联网系…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...