深入了解c语言中的结构体

介绍:

在C语言中,结构体是一种用户自定义的数据类型,它允许我们将不同类型的数据组合在一起,形成一个更为复杂的数据结构。结构体可以用来表示现实世界中的实体,如人员、学生、图书等。本篇博客将介绍结构体的基本概念、定义和使用方法。


结构体的基本概念:

什么是结构体:

结构体是一种由不同类型的数据组成的数据类型,它允许我们将多个相关的数据字段组合在一起,形成一个逻辑上的整体。

为什么需要结构体:

结构体使得我们可以更加灵活地组织数据,将相关的数据字段打包在一起,方便进行管理和操作。


 结构体的声明和定义:

结构体的声明:

在c语言中,结构体的声明使用struct关键字来定义,其一般形式如下:

struct
{数据类型 成员1;数据类型 成员2;// ... 更多成员
} 变量名;

例如, 定义一个表示学生信息的结构体可以如下所示:

struct Student 
{int id;//学号char name[20];//姓名float score;//分数
};

结构体的定义 :

在声明结构体后,可以通过该结构体的名称来定义结构体变量,其一般形式如下:

struct 结构体名 变量名;

例如,定义一个学生的结构体变量可以如下设置:

struct Student stu1;

结构体的成员访问: 

可以使用成员访问运算符  来访问结构体变量的成员,例如:

stu1.id = 1001;
strcpy(stu1.name, "Alice");
stu1.score = 95.5;

在上面的示例中,我们分别给stu1的成员idnamescore赋值。

结构体的匿名声明:

在一些情况下,也可以直接在声明结构体变量的同时定义结构体,称为匿名声明,其形式如下:

struct 
{数据类型 成员1;数据类型 成员2;// ... 更多成员
} 变量名;

例如:

struct 
{int year;int month;int day;
} today;

但我建议还是少使用匿名声明,避免访问时遇到超过两个匿名的结构体,发生错误。


结构体的应用: 

结构体的初始化:

成员列表初始化是一种简洁的初始化结构体变量的方法,它允许我们在声明结构体变量的同时给成员赋初值。具体方法是在声明结构体变量时使用花括号{ }括起来的成员初始化列表。

// 定义一个包含姓名和年龄的结构体
struct Person 
{char name[20];int age;
};int main() 
{// 使用成员列表初始化结构体变量struct Person person1 = {"Alice", 25};// 可以只初始化部分成员struct Person person2 = {.age = 30};return 0;
}

使用memset函数进行初始化:

另一种初始化结构体变量的方法是使用memset函数,memset函数可以将一块内存空间设置为指定的值。当结构体变量中的所有成员都是基本数据类型时,可以使用memset函数将结构体变量的内存空间全部设置为0,达到初始化的效果。

#include <string.h>// 定义一个包含姓名和年龄的结构体
struct Person 
{char name[20];int age;
};int main() 
{// 使用memset函数初始化结构体变量struct Person person;memset(&person, 0, sizeof(person)); // 将person结构体变量的内存空间全部设置为0return 0;
}

需要注意的是,使用memset函数进行初始化时,结构体变量的所有成员都会被设置为0。如果结构体中包含指针等复杂类型的成员,使用memset函数进行初始化可能会导致意想不到的问题,因此在这种情况下最好使用成员列表初始化或者逐个赋值的方式进行初始化。

结构体的初始化方法可以根据具体的情况选择,成员列表初始化适用于简单的结构体变量初始化,而memset函数则可以用于对结构体变量进行快速的清零操作。


结构体的嵌套:

结构体的嵌套是指在一个结构体中包含另一个结构体作为其成员。这种嵌套的结构体可以帮助我们更好地组织和管理复杂的数据结构,使得代码更加清晰和易于维护。接下来我们将讨论结构体中嵌套结构体的用法,以及如何访问嵌套结构体的成员。

例如:

// 定义一个表示日期的结构体
struct Date 
{int day;int month;int year;
};// 定义一个表示学生的结构体,其中嵌套了日期结构体
struct Student 
{int id;char name[50];struct Date dob; // 嵌套了日期结构体
};

在上面的例子中,结构体Student中嵌套了结构体Date作为其成员。这样一来,Student结构体就包含了学生的ID、姓名以及出生日期等信息。

访问嵌套结构体成员:

要访问嵌套结构体的成员,可以使用成员访问运算符 来访问。例如:

struct Student s1;
s1.id = 1001;
strcpy(s1.name, "Alice");
s1.dob.day = 15; // 访问嵌套结构体的成员
s1.dob.month = 6;
s1.dob.year = 2000;

在上面的例子中,我们首先创建了一个Student类型的结构体s1,然后通过.运算符访问了嵌套在其中的Date结构体的成员,分别给出生日期的daymonthyear赋值。


结构体的指针:

当我们需要在程序中操作结构体变量时,使用指向结构体的指针是一种非常有效的方法。通过结构体指针,我们可以直接访问和修改结构体的成员,而无需对整个结构体进行复制或传递。以下是关于结构体指针的介绍:


结构体指针的定义和初始化:

在C语言中,我们可以使用以下语法定义一个指向结构体的指针:

struct Person 
{char name[50];int age;
};struct Person person1; // 定义一个结构体变量
struct Person *ptrPerson; // 定义一个指向结构体的指针ptrPerson = &person1; // 将指针指向结构体变量

通过指针访问结构体成员:

一旦我们有了指向结构体的指针,就可以使用箭头运算符(->)来访问结构体的成员:

ptrPerson->age = 25; // 通过指针修改结构体成员的值
printf("Name: %s, Age: %d", ptrPerson->name, ptrPerson->age); // 通过指针访问结构体成员的值

结构体指针在函数参数传递和动态内存分配等方面有着广泛的应用。通过传递结构体指针,我们可以避免在函数调用中复制整个结构体,提高程序的效率。同时,结构体指针也可以用于动态分配内存,允许我们在运行时动态创建和管理结构体对象。


结构体的高级应用:

结构体的位域:

结构体位域是C语言中一种特殊的结构体成员类型,它允许我们在一个结构体成员中存储多个字段,每个字段只占用指定数量的位。结构体位域可以用于优化内存空间的利用,尤其是在需要存储大量布尔类型数据或者需要节省内存空间时非常有用。

结构体位域的定义:

结构体位域的定义方式与普通结构体成员略有不同,需要在成员名后面加上冒号和位域长度。例如:

struct BitFieldStruct 
{unsigned int flag1 : 1; // 1位的位域unsigned int flag2 : 3; // 3位的位域// 其他成员...
};

结构体位域的使用方法:

定义了结构体位域后,可以像普通结构体成员一样使用:

struct BitFieldStruct b;
b.flag1 = 1;
b.flag2 = 3;

优化内存空间的使用:

结构体位域可以帮助节省内存空间,特别是在需要存储大量布尔类型数据时。例如,在需要存储开关状态的数据结构中,可以使用结构体位域来节省内存空间:

struct Flags 
{unsigned int flag1 : 1; // 1位,用于表示开关状态unsigned int flag2 : 1; // 1位,用于表示开关状态unsigned int flag3 : 1; // 1位,用于表示开关状态// 更多开关状态...
};

 在这个例子中,使用了3个1位的位域来表示3个开关状态,这样可以将这3个开关状态压缩到一个整数的存储空间中,从而节省内存。

注意事项:

  • 结构体位域的长度不能超过成员类型的长度,否则会产生未定义的行为。
  • 结构体位域的布局和大小取决于编译器的实现,可能在不同编译器上有不同的表现,因此在跨平台开发时需要特别注意。

结构体的对齐:

结构体对齐的原理是为了满足平台对数据类型访问的要求,例如某些平台要求访问特定数据类型的内存地址必须是特定值的倍数。这样做可以提高内存访问的效率,但有时也会导致内存空间的浪费。

在C语言中,可以使用#pragma pack指令来控制结构体的对齐方式。#pragma pack指令告诉编译器以指定的字节对齐方式对结构体进行打包。

#include <stdio.h>// 取消默认的对齐方式
#pragma pack(1)// 定义一个结构体
struct MyStruct 
{char a;int b;char c;
};int main() 
{// 输出结构体的大小printf("Size of MyStruct: %lu\n", sizeof(struct MyStruct));return 0;
}

在上述示例中,取消默认的对齐方式后,结构体MyStruct的大小是6字节。这是由于char类型通常为1字节,int类型通常为4字节,在取消对齐后,它们按照实际大小依次排列,因此结构体的大小为1(char) + 4(int) + 1(char) = 6 字节。

注意,pack()里面只能填入2的次方倍,如1,2,4,8,16 

希望该文章能帮助你理解结构体。 

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

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

相关文章

2023版本idea插件开发踩坑记录(一)

在进行idea开发的时候&#xff0c;开始仿照着写第一个插件hello world的时候&#xff0c;运行的时候一直运行不成功。参考了很多博客都是如此 后面对官方文档读了一遍&#xff0c;就发现其中的原委&#xff0c;这个的话估计会有很多人跟我一样踩坑 具体原因是&#xff0c;idea插…

python之pyqt专栏11-事件(QEvent)

QApplication.exec() 在main.py中&#xff0c;实例化app对象&#xff0c;然后在 sys.exit(app.exec())中调用app.exec()&#xff0c; if __name__ __main__:# 实例化应用app QApplication(sys.argv)# 实例化MyMainFormmyw MyMainForm()myw.show()# 启动应用程序的事件循环并…

selenium使用记录

本文记录python环境下使用selenium的一些步骤 Step1&#xff1a;安装并配置驱动 pip install selenium # 使用pip在对应python中安装selenium包为了让selenium能调用指定的浏览器&#xff0c;需要下载对应浏览器的驱动程序&#xff08;这里以edge为例子&#xff09; #Firefo…

Git 分支详解

目录 1. Git 分支管理 2. 如何自己创建分支&#xff1f; 3. 创建分支修改内容&#xff0c;之后合并到主分支 4. 删除分支 5. 出现 merge 冲突如何解决 6. 分支策略 前言 之前只是知道有 master 分支这个东西&#xff0c;但是具体是啥意思还是不知道&#xff0c;今天详…

卫星影像数据查询网址(WORLDVIEW1/2/3/4、PLEIADES、SPOT系列、高景、高分1-7、资源系列、吉林一号等)

商业卫星影像数据查询网址&#xff08;WORLDVIEW1/2/3/4、PLEIADES、SPOT系列、高景、高分1-7、资源系列、吉林一号等&#xff09; 1、资源卫星应用中心 网址&#xff1a;http://www.cresda.com/CN/ 可查询国产高分1、2、3、4、5、6、7号卫星&#xff0c;资源三号、资源三号…

用HeidiSQL在MySQL中新建用户

用HeidiSQL登录到MySQL数据库&#xff0c;注意登录的时候要使用有权限的用户&#xff1a; 选择工具-》用户管理&#xff1a; 点击左上角的“添加”&#xff1a; 输入用户名、密码&#xff0c;并且分配权限&#xff1a; 点击右边的“添加对象”&#xff1a; 可以根据自己…

系统托盘区句柄研究和C#基本托盘编程

因为我的系统托盘区小图标有时候会不可见,在还是在; 研究一下系统托盘区的句柄,是否每个小图标是一个单个窗口,就像form的button一样; 下图句柄工具,把问号拖动到窗口上,就会显示该窗口的句柄和窗口类等信息; 拖到系统托盘区看一下;拖到任何一个小图标上面,都只显示…

使用VC++设计程序实现K近邻中值滤波器(KNNMF)、最小均方差滤波器、矢量中值滤波算法进行滤波

VC实现若干种图像滤波技术2 获取源工程可访问gitee可在此工程的基础上进行学习。 该工程的其他文章&#xff1a; 01- 一元熵值、二维熵值 02- 图像平移变换&#xff0c;图像缩放、图像裁剪、图像对角线镜像以及图像的旋转 03-邻域平均平滑算法、中值滤波算法、K近邻均值滤波器 …

【Flink】容错机制

目录 1、检查点 ​编辑1.1 检查点的保存 1.1.1 周期性的触发保存 1.1.2 保存的时间点 1.1.3 时间点的保存与恢复 1.1.3.1保存 ​编辑 1.1.3.2 恢复的具体步骤: 1.2 检查点算法 1.2.1 检查点分界线(Barrier) 1.2.2 分布式快照算法(Barrier对齐的精准一次) 1.2.…

HTML简介

1&#xff0c;网页 网页的相关概念 1.1&#xff0c;什么是网页&#xff1f; 网页是构成网站的基本元素&#xff0c;它通常由图片&#xff0c;链接&#xff0c;文字&#xff0c;声音&#xff0c;视频等元素组成。其实就是一个常见以.htm或.html后缀结尾的文件&#xff0c;因此…

页面表格高度自适应

前言 现在后端管理系统主页面基本都是由三部分组成 查询条件&#xff0c;高度不固定&#xff0c;可能有的页面查询条件多&#xff0c;有的少表格&#xff0c;高度不固定&#xff0c;占据页面剩余高度分页&#xff0c;高度固定 这三部分加起来肯定是占满全屏的&#xff0c;那么我…

零基础上手,秒识别检测,IDEA研究院发布全新T-Rex模型

目标检测作为当前计算机视觉落地的热点技术之一&#xff0c;已被广泛应用于自动驾驶、智慧园区、工业检测和卫星遥感等场景。开发者在研究相关目标检测技术时&#xff0c;通常需熟练掌握图像目标检测框架&#xff0c;如通用目标检测框架 YOLO 系列&#xff0c;旋转目标检测框架…

『Nginx安全访问控制』利用Nginx实现账号密码认证登录的最佳实践

&#x1f4e3;读完这篇文章里你能收获到 如何创建用户账号和密码文件&#xff0c;并生成加密密码配置Nginx的认证模块&#xff0c;实现基于账号密码的登录验证 文章目录 一、创建账号密码文件1. 安装htpasswd工具1.1 CentOS1.2 Ubuntu 二、配置Nginx三、重启Nginx 在Web应用程…

SpringAMQP入门案例——发送消息

依赖 <!--SpringAMQP起步依赖--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency> yml配置文件 自行修改 spring:rabbitmq:host: 192.168.220.130 # …

CyclicBarrier实战应用——批量数据多线程协调异步处理(子线程执行事务回滚)

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; CountDownLatch实战应用——批量数据多线程协调异步处理(子线程执行事务…

【源码篇】基于SpringBoot+thymeleaf实现的大学生自习室座位预定系统

文章目录 系统介绍管理员学生 技术选型成果展示账号地址及其他说明 系统介绍 基于SpringBootthymeleaf实现的大学生自习室座位预定系统是为座位管理打造的一款在线管理平台&#xff0c;它可以实时完成信息处理&#xff0c;使其系统化和规范化。 系统功能说明 管理员 1、用户…

误用STM32串口发送标志位 “USART_FLAG_TXE” “USART_FLAG_TC”造成的BUG

当你使用串口发送数据时是否出现过这样的情况&#xff1a; 1.发送时第一个字节丢失。 2.发送时出现莫名的字节丢失。 3.各种情况字节丢失。 1.先了解一下串口发送的流程图&#xff08;手动描绘&#xff09;&#xff1a; 可以假想USART_FLAG_TXE是用于检测"弹仓"&…

【STM32F103】GPIO通用输入输出口

GPIO 简介 GPIO&#xff08;General Purpose Input Output&#xff09;通用输入输出口是微控制器&#xff08;MCU&#xff09;必备的片上外设&#xff0c;可以实现微控制器与外部设备的数字交换。 STM32F103系列的芯片最多可以提供112个多功能双向IO引脚&#xff0c;但是显然…

机器学习-回归问题(Regression)

前言 与KNN分类任务预测的输出为离散型不同. 在机器学习中&#xff0c;回归任务是用于预测连续数值型变量的任务。回归任务在很多领域都有着广泛的应用. 回归问题求解 在一个回归问题中&#xff0c;很显然模型选择和好坏会直接关系到将来预测结果的接近程度&#xff0c;举个…

规则引擎专题---2、开源规则引擎对比

开源规则引擎 开源的规则引擎整体分为下面几类&#xff1a; 通过界面配置的成熟规则引擎&#xff0c;这种规则引擎相对来说就比较重&#xff0c;但功能全&#xff0c;比较出名的有:drools, urule。 基于jvm脚本语言&#xff0c;互联网公司会觉得drools太重了&#xff0c;然后…