C语言——结构体
一、结构体的创建
1、定义
在 C 语言中,结构体是一种自定义的数据类型,它允许将不同类型的数据项组合成一个单一实体。这在组织复杂数据时非常有用,因为它可以将有逻辑关系的数据组合在一起。结构体是一些值的集合,这些值是结构成员变量。
2、结构体的声明格式
结构体定义由关键字 struct 和结构体名组成,结构体名可以根据需要自行定义。
struct tag {member-listmember-listmember-list ...
} variable-list ;struct 结构体标签
{变量定义;变量定义;变量定义;...
} 结构变量;
tag 是结构体标签。
member-list 是标准的变量定义,比如 int i; 或者 float f;,或者其他有效的变量定义。
variable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。
在一般情况下,tag、member-list、variable-list 这 3 部分至少要出现 2 个。
3、结构体的声明实例
(1)没有具体标签(匿名)
//此声明声明了拥有3个成员的结构体,分别为int类型的a,char类型的的b和double类型的c//同时又声明了结构体变量s1//这个结构体并没有标明其标签struct{int a;char b;double c;} s1;
(2)有具体标签
//此声明声明了拥有3个成员的结构体//结构体的标签被命名为Student,没有声明变量struct Student{int age;char name[20];int height;};
(3)同时声明变量
//此声明声明了拥有3个成员的结构体//结构体的标签被命名为Person,同时声明变量struct Person{int age;char name[20];int height;};
在上面的声明中,第二个和第三个声明被编译器当作两个完全不同的类型,即使他们的成员列表是一样的。因为它们的标签名不一样,即使两个结构体的成员列表完全相同,如果它们被声明为不同的类型(即使是匿名的),那么它们仍然是不同的类型。
4、结构体变量的初始化
在C语言中,当您定义一个结构体时,可以为其成员变量提供初始值。这种操作称为结构体的初始化。初始化时,您可以使用大括号{}
来包含一系列初始化器,这些初始化器的顺序应当与结构体定义中的成员声明顺序一致。每个初始化器由逗号分隔。
(1)基本的结构体定义和初始化:
struct Person {int age;char name[20];int height;
};struct Person z = { 18, "zhangsan", 180 };
(2)匿名结构体的定义和初始化
为了声明一个匿名结构体的实例,需要先给结构体定义一个别名,或者直接在声明时提供一个变量名。如果想要声明一个匿名结构体并立即创建一个该类型的实例,可以用下列方法:
(i)直接在声明时初始化结构体变量:
struct {int age;char name[20];int height;
} z = { 18, 'zhangsan', 180 };
(ii)给匿名结构体定义一个别名:
typedef struct
{int age;char name[20];int height;
} Person;Person z = { 18, "zhangsan", 180 };
Person w = { 19, "wanger", 190 };
这里初始化变量时不能用:
struct Person z = { 18, "zhangsan", 180 };
这是错误的。
因为使用了typedef
,所以在定义变量时应该直接使用别名Person
,而不是struct Person
。正确的声明应该是:
Person z = { 18, "zhangsan", 180 };
如果使用struct Person
,编译器会认为你正在尝试声明一个新的、不同的结构体类型,它没有找到这个新类型的定义,因此会报告“不完整的类型”的错误。
这与有标签的结构体不同。
5、结构体的成员
(1)成员种类
在C语言中,结构体的成员可以是几乎任何类型,包括:
-
基本数据类型:如
int
,float
,double
,char
等。 -
数组类型:可以是基本数据类型的数组,例如
int numbers[10];
,也可以是结构体类型的数组。 -
指针类型:包括指向基本数据类型、数组、其他结构体或者函数的指针。
-
结构体类型:
- 同类型的结构体指针(因为直接包含同类型的结构体会造成无限大小的定义)。
- 其他类型的结构体或结构体数组,常用于嵌套结构体。
-
联合体(union)类型:可以包含联合体,它是一种特殊的数据结构,允许在相同的内存位置存储不同的数据类型。
-
枚举类型(enum):可以包含枚举类型成员,用于表示成员变量只能取有限个命名的整数值。
-
函数指针类型:可以包含指向函数的指针,这允许结构体“拥有”可以调用的函数。
下面是一个包含不同类型成员的结构体示例:
#include <stdio.h>// 声明一个枚举类型
enum Color
{ RED, GREEN, BLUE
};// 定义一个结构体类型
struct Example
{int integer; // 基本数据类型double floating_point; // 基本数据类型char character; // 基本数据类型char string[100]; // 数组类型int *pointer; // 指针类型struct Nested{float nested_floating_point;} nested_struct; // 嵌套结构体类型union{int union_int;float union_float;} union_member; // 联合体类型enum Color color; // 枚举类型void (*function_pointer)(void); // 函数指针类型
};// 一个简单的函数,之后会被赋给结构体中的函数指针
void simpleFunction()
{printf("Hello from simpleFunction!\n");
}int main()
{struct Example example;example.integer = 10;example.floating_point = 3.14;example.character = 'A';example.string[0] = '\0'; // 初始化字符串为空字符串int value = 20;example.pointer = &value; // 指向value的指针example.nested_struct.nested_floating_point = 2.71;example.union_member.union_float = 5.55f; // 使用联合体的float成员example.color = RED; // 枚举类型成员赋值example.function_pointer = simpleFunction; // 函数指针赋值// 使用函数指针调用函数example.function_pointer();return 0;
}
(2)结构体内包含其他结构体或包含指向自己结构体类型的指针
结构体的成员可以包含其他结构体,也可以包含指向自己结构体类型的指针,而通常这种指针的应用是为了实现一些更高级的数据结构如链表和树等。
以下是一个使用自引用指针的结构体定义,这个结构体可以用来实现一个简单的单向链表节点:
#include <stdio.h>struct ListNode
{int value; // 这个节点存储的数据struct ListNode* next; // 指向下一个节点的指针
};int main()
{// 创建链表节点struct ListNode node1;node1.value = 1;node1.next = NULL; // 目前链表只有一个节点,所以next指向NULL// 添加第二个节点struct ListNode node2;node2.value = 2;node2.next = NULL;// 将第一个节点的next指针指向第二个节点node1.next = &node2;// 现在,node1.next指向node2,形成了一个包含两个节点的链表return 0;
}
如果两个结构体互相包含,则需要对其中一个结构体进行不完整声明,如下所示:
struct B;//对结构体B进行不完整声明 struct A//结构体A中包含指向结构体B的指针{struct B* partner;//other members;};//结构体B中包含指向结构体A的指针,在A声明完后,B也随之进行声明struct B{struct A* partner;//other members;};
二、结构体的使用
1、. 点操作符(成员访问操作符)
格式:
结构体变量.成员
实例:
#include <stdio.h>struct Student
{char name[20];double height;int age;
};int main()
{struct Student a = {"xiaoa",1.80,19};printf("%s %lf %d",a.name,a.height,a.age);return 0;
}
运行结果:
也可以使用指针,但 . 操作符的优先级大于 * 操作符,要加()
#include <stdio.h>struct Student
{char name[20];double height;int age;
};int main()
{struct Student a = {"xiaoa",1.80,19};struct Student* pa = &a;printf("%s %lf %d",(*pa).name,(*pa).height,(*pa).age);return 0;
}
运行结果:
2、->箭头操作符(成员访问操作符)
格式:
结构体变量的指针->成员
实例:
#include <stdio.h>struct Student
{char name[20];double height;int age;
};int main()
{struct Student a = {"xiaoa",1.80,19};struct Student* pa = &a;printf("%s %lf %d\n",pa->name,pa->height,pa->age);return 0;
}
运行结果:
三、结构体做函数参数
1、直接传结构体变量
这种方法占用内存和时间较多,因为要将实参拷贝成形参需要时间,形参存储需要内存空间。
#include <stdio.h>struct Student//定义结构体
{char name[20];double height;int age;
};void print(struct Student student)//定义函数
{printf("名字 %s\n",student.name);printf("身高 %lf\n", student.height);printf("年龄 %d\n", student.age);
}int main()
{struct Student a = {"xiaoa",1.80,19};//定义和初始化结构变量astruct Student b = {"xiaob",1.85,18};//定义和初始化结构变量bprint(a);//利用print函数输出结构变量aprint(b);//利用print函数输出结构变量breturn 0;
}
运行结果:
2、传结构体变量的指针
这种方法更节省空间,不用创建形参。
#include <stdio.h>struct Student//定义结构体
{char name[20];double height;int age;
};void print(struct Student *student)
{printf("名字 %s\n", student->name);printf("身高 %lf\n", student->height);printf("年龄 %d\n", student->age);
}int main()
{struct Student a = { "xiaoa",1.80,19 };//定义和初始化结构变量astruct Student b = { "xiaob",1.85,18 };//定义和初始化结构变量bprint(&a);//传入结构体变量a的地址print(&b);//传入结构体变量b的地址return 0;
}
运行结果:
相关文章:

C语言——结构体
一、结构体的创建 1、定义 在 C 语言中,结构体是一种自定义的数据类型,它允许将不同类型的数据项组合成一个单一实体。这在组织复杂数据时非常有用,因为它可以将有逻辑关系的数据组合在一起。结构体是一些值的集合,这些值是结构…...

基于多反应堆的高并发服务器【C/C++/Reactor】(中)Buffer的创建和销毁、扩容、写入数据
TcpConnection:封装的就是建立连接之后得到的用于通信的文件描述符,然后基于这个文件描述符,在发送数据的时候,需要把数据先写入到一块内存里边,然后再把这块内存里边的数据发送给客户端,除了发送数据,剩下…...

【Linux】常用的基本命令指令①
前言:从今天开始,我们逐步的学习Linux中的内容,和一些网络的基本概念,各位一起努力呐! 💖 博主CSDN主页:卫卫卫的个人主页 💞 👉 专栏分类:数据结构 👈 💯代码…...
活动运营常用的ChatGPT通用提示词模板
活动目标确定:如何明确活动的目标,确保活动策划与执行的方向性? 活动主题选择:如何选择吸引人的活动主题,提高用户的参与度和兴趣? 活动形式策划:如何根据活动目标和主题,选择适合…...
SpringBoot 中实现订单30分钟自动取消的策略
简介 在电商和其他涉及到在线支付的应用中,通常需要实现一个功能:如果用户在生成订单后的一定时间内未完成支付,系统将自动取消该订单。 本文将详细介绍基于Spring Boot框架实现订单30分钟内未支付自动取消的几种方案,并提供实例…...

像专家一样使用TypeScript映射类型
掌握TypeScript的映射类型,了解TypeScript内置的实用类型是如何工作的。 您是否使用过Partial、Required、Readonly和Pick实用程序类型? 你知道他们内部是怎么运作的吗? 如果您想彻底掌握它们并创建自己的实用程序类型,那么不要错过本文所涵盖的内容。…...
Golang 结构体
前言 在 Go 语言中,结构体(struct)是一种自定义的数据类型,将多个不同类型的字段(fields)组合在一起 结构体通常用于模拟真实世界对象的属性和行为 定义结构体 可以使用 type 关键字和 struct 关键字来定…...

服务器运行状况监控工具
服务器运行状况监视提供了每个服务器状态和性能的广泛概述,通过监控服务器指标,如 CPU 使用率、内存消耗、I/O、磁盘使用率、进程等,服务器运行状况监控可以避免服务器停机。 服务器性能监控指标 服务器是网络中最重要的组件之一࿰…...
2022年全国职业院校技能大赛软件测试赛题卷②—自动化测试解析报告(含术语)
2022年全国职业院校技能大赛软件测试任务四 自动化测试 目录 第一题:按照以下步骤在PyCharm中进行自动化测试脚本编写,并执行脚本。...

497 蓝桥杯 成绩分析 简单
497 蓝桥杯 成绩分析 简单 //C风格解法1,*max_element()与*min_element()求最值 //时间复杂度O(n),通过率100% #include <bits/stdc.h> using namespace std;using ll long long; const int N 1e4 …...

一、HTML5简介
一、简介 超文本标记语言(英语:HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言。可以使用 HTML 来建立自己的 WEB 站点,HTML 运行在浏览器上,由浏览器来解析。 <!…...

视频云存储/视频智能分析平台EasyCVR在麒麟系统中无法启动该如何解决?
安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…...

前端性能优化之图像优化
图像优化问题主要可以分为两方面:图像的选取和使用,图像的加载和显示。 图像基础 HTTP Archive上的数据显示,网站传输的数据中,60%的资源都是由各种图像文件组成的,当然这些是将各类型网站平均的结果,单独…...

微信小程序封装vant 下拉框select 单选组件
先上效果图: 主要是用vant 小程序组件封装的:vant 小程序ui网址:vant-weapp 主要代码如下: 先封装子组件: select-popup 放在 components 文件夹里面 select-popup.wxml: <!--pages/select-popup/select-popup.wxml--> &…...
c语言试卷
江西财经大学IT帮 2020-2021第一学期期末C语言模拟考试试卷 课程名称:C语言程序设计(软件)(主干课程) 适用对象:21级本科 试卷命题人 钟芳盛 游天悦 李俊贤 万军豪 张位 试卷审核人 钟芳盛 一、单项…...

文献阅读:Sparse Low-rank Adaptation of Pre-trained Language Models
文献阅读:Sparse Low-rank Adaptation of Pre-trained Language Models 1. 文章简介2. 具体方法介绍 1. SoRA具体结构2. 阈值选取考察 3. 实验 & 结论 1. 基础实验 1. 实验设置2. 结果分析 2. 细节讨论 1. 稀疏度分析2. rank分析3. 参数位置分析4. 效率考察 4.…...

NCC基础开发技能培训
YonBuilder for NCC 是一个带插件的eclipse工具,跟eclipse没什么区别 NC Cloud2021.11版本开发环境搭建改动 https://nccdev.yonyou.com/article/detail/495 不管是NC Cloud 新手还是老NC开发,在开发NC Cloud时开发环境搭建必看!ÿ…...

Flink中的状态管理
一.Flink中的状态 1.1 概述 在Flink中,算子任务可以分为有状态和无状态两种状态。 无状态的算子任务只需要观察每个独立事件,根据当前输入的数据直接转换输出结果。例如Map、Filter、FlatMap都是属于无状态算子。 而有状态的算子任务,就…...

【linux】线程互斥
线程互斥 1.线程互斥2.可重入VS线程安全3.常见锁的概念 喜欢的点赞,收藏,关注一下把! 1.线程互斥 到目前为止我们学了线程概念,线程控制接下来我们进行下一个话题,线程互斥。 有没有考虑过这样的一个问题,…...

机器学习原理到Python代码实现之LinearRegression
Linear Regression 线性回归模型 该文章作为机器学习的第一篇文章,主要介绍线性回归模型的原理和实现方法。 更多相关工作请参考:Github 算法介绍 线性回归模型是一种常见的机器学习模型,用于预测一个连续的目标变量(也称为响应变…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...