深入了解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结构体变量的内存空间全部设置为0

    return 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.mfbz.cn/a/211817.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

iceoryx(冰羚)-进程间消息同步

iceoryx进程间消息同步 iceoryx进程间消息同步&#xff0c;是用socket或管道实现的,定义在iceoryx\iceoryx_posh\include\iceoryx_posh\internal\runtime\ipc_interface_base.hpp namespace platform { #if defined(_WIN32) using IoxIpcChannelType iox::posix::NamedPipe; …

Linux下为可执行文件添加图标

Ubuntu 18.04上使用Qt5.14.2创建一个简单的Qt Widgets项目test&#xff0c;添加2个Push Button按钮&#xff0c;点击分别获取github和csdn地址&#xff0c;在mainwindow.cpp中添加的代码如下: #include "mainwindow.h" #include "ui_mainwindow.h" #inclu…

Linux 互斥锁 读写锁 条件变量 信号量 (备查)

线程同步 1&#xff09;所谓的同步并不是多个线程同时对内存进行访问&#xff0c;而是按照先后顺序依次进行的。 2&#xff09;如没有对线程进行同步处理&#xff0c;会导致多个线程访问共享资源出现数据混乱的问题。 3&#xff09;所谓共享资源就是多个线程共同访问的变量&…

javaweb校车校园车辆管理系统springboot+jsp

结构设计&#xff1a;总体采用B/S结构设计模式 (1)用户登录模块&#xff1a;用户通过手动登录&#xff0c;检测是否是校内人员的车辆。 (2)用户车辆信息编辑、上传、模块&#xff1a;通过上传车辆入场信息的操作权限&#xff0c;以用户的名义发布资料上传至校园停车场系统中。…

可视化数据库管理客户端:Adminer

简介&#xff1a;Adminer&#xff08;前身为phpMinAdmin&#xff09;是一个用PHP编写的功能齐全的数据库管理工具。与phpMyAdmin相反&#xff0c;它由一个可以部署到目标服务器的文件组成。Adminer可用于MySQL、PostgreSQL、SQLite、MS SQL、Oracle、Firebird、SimpleDB、Elast…

Java+SSM+MySQL基于微信的在线协同办公小程序(附源码 调试 文档)

基于微信的在线协同办公小程序 一、引言二、系统设计三、技术架构四、管理员功能设计五、员工功能设计六、系统实现七、界面展示八、源码获取 一、引言 随着科技的飞速发展&#xff0c;移动互联网已经深入到我们生活的各个角落。在这个信息时代&#xff0c;微信作为全球最大的…

头歌JUnit单元测试相关实验入门

一、入门实验 1.1第一个Junit测试程序 任务描述 请学员写一个名为testSub()的测试函数&#xff0c;来测试给定的减法函数是否正确。 相关知识 Junit编写原则 1、简化测试的编写&#xff0c;这种简化包括测试框架的学习和实际测试单元的编写。 2、测试单元保持持久性。 3、利用…

【Python】Python给工作减负-读Excel文件生成xml文件

目录 ​前言 正文 1.Python基础学习 2.Python读取Excel表格 2.1安装xlrd模块 2.2使用介绍 2.2.1常用单元格中的数据类型 2.2.2 导入模块 2.2.3打开Excel文件读取数据 2.2.4常用函数 2.2.5代码测试 2.2.6 Python操作Excel官方网址 3.Python创建xml文件 3.1 xml语法…

计算机组成原理,硬件组成,存储器,控制器,控制器的任务, 运算器,中央处理器CPU,主存

计算机组成原理 课程需求 前导课程&#xff1a; 后继课程 汇编 操作系统 数逻 组成 系统结构 数电 微机原理 课程结构 计算机特性 1 从外部角度来看计算机的特性 快速 通用 准确 逻辑 2从外部特性与内部特性的关系 计算机组成 一 硬件组成 运算器 主要功能是进行算术…

强化学习(一)——基本概念及DQN

1 基本概念 智能体 agent &#xff0c;做动作的主体&#xff0c;&#xff08;大模型中的AI agent&#xff09; 环境 environment&#xff1a;与智能体交互的对象 状态 state &#xff1b;当前所处状态&#xff0c;如围棋棋局 动作 action&#xff1a;执行的动作&#xff0c;…

CRM系统是怎样帮助销售流程自动化的?

销售业绩是衡量企业经营的重要指标&#xff0c;也是销售人员一直要达成的目标。销售业绩能否提高取决于销售人员的能力、客户服务水平&#xff0c;还需要借助有效的工具。CRM系统就是这样的一款软件。企业如何提高销售业绩&#xff1f;不妨试试CRM销售流程自动化。 CRM如何实现…

【从删库到跑路 | MySQL总结篇】事务详细介绍

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【MySQL学习专栏】&#x1f388; 本专栏旨在分享学习MySQL的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录 一、事务…

JavaScript 数据结构

JavaScript 数据结构 目录 JavaScript 数据结构 一、标识符 二、关键字 三、常量 四、变量 每一种计算机编程语言都有自己的数据结构&#xff0c;JavaScript脚本语言的数据结构包括&#xff1a;标识符、常量、变量、保留字等。 一、标识符 标识符&#xff0c;说白了&…

使用gcloud SDK 管理和部署 Cloud run service

查看cloud run 上的service 列表&#xff1a; gcloud run services list > gcloud run services listSERVICE REGION URL LAST DEPLOYED BY LAST DEPL…

【QT】Windows环境下,cmake引入QML

这里使用的QT库为5.7版本。 1、添加环境变量 QT库根目录环境变量 QTDIR QT库平台插件环境变量 QT_PLUGIN_PATH QML支持环境变量 QML2_IMPORT_PATH &#xff08;该环境变量仅在需要使用QML时添加&#xff09; QT库动态库环境变量&#xff0c;bin目录下包含了QT程序运行所需的dl…

常见的攻击防护

只做模拟机器使用&#xff0c;不使用真实机器 目录 一、 DHCP饿死和防护应对措施.................................. 1 1&#xff0c; 实验拓扑&#xff1a;...................................................... 2 2&#xff0c; 实验配置............................…

AD23等间距拉线、布线的方法

U M 键进行多根走线&#xff0c; 多根走线想保持10个mil 我可以直接按table键,弹出Multi-Routing ponent&#xff0c;项的Bus Spadng输入框中填充10个mil&#xff0c;新走线产生10个mil的等间距 保持最小的一个规则&#xff0c;可以去到6mil线距。 在拉线操作过程中&#…

详解Spring中BeanPostProcessor在Spring工厂和Aop发挥的作用

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…

TCP连接为什么是三次握手,而不是两次和四次

答案 阻止重复的历史连接同步初始序列号避免资源浪费 原因 阻止重复的历史连接&#xff08;首要原因&#xff09; 考虑这样一种情况&#xff1a; 客户端现在要给服务端建立连接&#xff0c;向服务端发送了一个SYN报文段&#xff08;第一次握手&#xff09;&#xff0c;以表示请…

Mininet学习记录(常用命令+创建网络拓扑+OpenDaylight显示拓扑结构)

目录 1.Mininet简介2.Mininet常用命令2.1创建网络拓扑常用参数2.2常用的内部交换命令 3.创建网络拓扑的三种方式3.1通过命令行创建3.2通过miniedit可视化界面创建3.3通过python脚本创建 4.问题总结 1.Mininet简介 Mininet 是由一些虚拟的终端节点 (end-hosts) 、交换机、路由器…