c语言回顾-结构体

前言

在前面的学习中,我们知道C语言提供了许多内置类型,如:char、short、int、long、float、double等,但是只有这些内置类型还是不够的。当我们想描述学生,描述一本书,这时单一的内置类型是不行的。描述一个学生需要名字、年龄、学号、身高、体重等;描述一本书需要作者、出版社、定价等。C语言为了解决这个问题,增加了结构体这种自定义的数据类型,让我们可以自己创造适合的类型。

结构体的定义

结构体是一种用户自定义的数据类型,用于将多个不同类型的数据组合在一起形成一个新的数据类型。结构体由多个成员变量组成,每个成员变量可以是不同的数据类型,可以是基本数据类型(如整型、浮点型、字符型等)或其他结构体类型。结构体的成员变量在内存中是按照声明的顺序依次存储的。

1.结构的声明

定义结构体的语法如下:

struct 结构体名 {

类型 成员1;

类型 成员2; ... };

通过定义结构体,可以创建结构体变量,用于存储结构体类型的数据。结构体变量的定义语法如下:

struct 结构体名 变量名;

当然也可以直接在{}后面命名(后面会讲到)

假设我们有一个描述学生的结构体:

struct Student {
int id;
char name[50];
int age;
float score; };

2.结构体变量的定义和初始化

//代码1:变量的定义
struct Point
{
 int x;
 int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//代码2:初始化。
struct Point p3 = {10, 20};
struct Stu //类型声明
{
 char name[15];//名字
 int age; //年龄
};
struct Stu s1 = {"zhangsan", 20};//初始化
struct Stu s2 = {.age=20, .name="lisi"};//指定顺序初始化
//代码3
struct Node
{
 int data;
 struct Point p;
 struct Node* next; 
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化

下面具体介绍下初始化方法:

假设我们有一个描述学生的结构体:

struct Student {
    int id;
    char name[50];
    int age;
    float score;
};

1.可以定义了一个名为student1Student类型的结构体变量,然后通过点操作符.对结构体的各个成员变量进行逐个初始化。

struct Student student1; // 定义结构体变量
student1.id = 1001; // 初始化成员变量
strcpy(student1.name, "Alice"); // 初始化成员变量
student1.age = 20; // 初始化成员变量
student1.score = 85.5; // 初始化成员变量

2.除了逐个初始化,还可以使用一种更简洁的方式,即在定义结构体变量时直接初始化

struct Student student2 = {1002, "Bob", 21, 90.0}; // 定义结构体变量并初始化

3.还有一种初始化结构体变量的方式是使用指定成员的方式进行初始化

struct Student student3 = {.id = 1003, .name = "Charlie", .age = 22, .score = 95.0}; // 指定成员进行初始化

在这种方式中,我们使用成员名来指定要初始化的成员变量,这样可以更清晰地表达出初始化的意图。

无论是逐个初始化、直接初始化,还是指定成员初始化,都可以根据实际情况选择合适的方式来初始化结构体变量,以满足需求。

结构体嵌套初始化

struct Point
{
 int x;
 int y;
}
struct Node
{
 int data;
 struct Point p;
 struct Node* next; 
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化

Node结构体中包含Point结构体,需要注意的是,嵌套结构体的初始化顺序应与结构体定义中的成员顺序一致,以确保正确地对应初始化。

3.结构成员访问

3.1结构体成员的直接访问

结构体成员的直接访问是通过点操作符(.)访问的。点操作符接受两个操作数。
#include <stdio.h>
struct Point
{
 int x;
 int y;
}p = {1,2};
int main()
{
 printf("x: %d y: %d\n", p.x, p.y);
 return 0;
}
使用方式:结构体变量.成员名

3.2结构体成员的间接访问

有时候我们得到的不是一个结构体变量,而是得到了一个指向结构体的指针。
#include <stdio.h>
struct Point
{
 int x;
 int y;
};
int main()
{
 struct Point p = {3, 4};
 struct Point *ptr = &p;
 ptr->x = 10;
 ptr->y = 20;
 printf("x = %d y = %d\n", ptr->x, ptr->y);
 return 0;
}
使用方式:结构体指针->成员名
综合例子
#include <stdio.h>
#include <string.h>
struct Stu
{
 char name[15];//名字
 int age; //年龄
};
void print_stu(struct Stu s)
{
 printf("%s %d\n", s.name, s.age);
}
void set_stu(struct Stu* ps)
{
 strcpy(ps->name, "李四");
 ps->age = 28;
}
int main()
{
 struct Stu s = { "张三", 20 };
 print_stu(s);
 set_stu(&s);
 print_stu(s);
 return 0;
}

4.结构的特殊声明

在声明结构的时候,可以不完全的声明。
⽐如:
//匿名结构体类型
struct
{
 int a;
 char b;
 float c;
}x;
struct
{
 int a;
 char b;
 float c;
}a[20], *p;
匿名结构体是指在定义结构体变量时不指定结构体名称,直接定义结构体的成员变量。这样定义的结构体没有结构体名,只有成员变量名。

匿名结构体常用于临时的、不需要重复使用的数据结构,可以在需要时直接定义和使用,无需为命名。

需要注意的是,由于匿名结构体没有结构体名称,因此无法在其他地方再次定义相同的结构体类型。匿名结构体的作用范围仅限于定义该结构体的作用域内。

5.结构的自引用

在结构中包含一个类型为该结构本身的成员是否可以呢?
比如,定义一个链表的节点:
struct Node
{
int data;
struct Node next;
};
上述代码正确吗?如果正确,那 sizeof(struct Node) 是多少?
仔细分析,其实是不行的,因为一个结构体中再包含一个同类型的结构体变量,这样结构体变量的大小就会无穷的大,是不合理的。

结构体的自引用是指在结构体定义中包含对自身类型的成员变量。

在C语言中,结构体的自引用可以通过使用指针来实现。为了在结构体中引用自身类型,需要先定义一个指向自身类型的指针成员变量。

正确的自引用方式:
struct Node {
    int data;
    struct Node* next;  // 指向自身类型的指针成员变量
};

在上述示例中,结构体Node包含一个整型成员变量data和一个指向自身类型struct Node的指针成员变量next。这样就实现了结构体的自引用。

自引用的结构体常用于构建链表、树等数据结构。通过指针成员变量,可以将多个结构体实例链接在一起形成复杂的数据结构。(详细结构请友友们参照数据结构的相关内容理解)

在结构体自引用使用的过程中,夹杂了 typedef 对匿名结构体类型重命名,也容易引⼊问题,看看
下面的代码,可行吗?
typedef struct
{
int data;
Node* next;
}Node;
答案是 不行的,因为Node是对前面的匿名结构体类型的重命名产生的,但是在匿名结构体内部提前使用Node类型来创建成员变量,这是不行的。
故定义结构体不要使用匿名结构体了
typedef struct Node
{
 int data;
 struct Node* next;
}Node;

结束语

本节内容小编对结构体的大部分内容都做了详细的解释,相信大家都对结构体有了了解,下节内容小编将带领大家进一步理解结构体的大小,如何计算,遵循什么规则等!

支持小编的留下赞赞和评论吧,感谢大家!!!

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

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

相关文章

Linux---系统的初步学习【项目一:Linux操作系统的安装与配置】

项目一 Linux操作系统的安装与配置 1.1 项目知识准备 1.1.1 操作系统是什么&#xff1f; ​ 操作系统&#xff08;Operating System&#xff0c;OS&#xff09;是管理计算机硬件与软件资源的计算机程序。操作系统需要处理如管理硬件、决定程序运行的优先次序、管理文件系统等…

逻辑斯蒂回归与最大熵

知识树 感知机的缺陷 修补感知机缺陷-逻辑斯蒂回归 下面这两个值是强制给的,不是推导的 最大熵 最大熵的一个小故事 最大熵模型 我们最终目标是要求P(Y|X) 书上写的是H,但是2我们认为H(Y|X)更合适 咱们最终的目的是要用拉格朗日乘数法,所以需要约束 总结 感觉深度之眼比较模…

汽车级TPSI2140QDWQRQ1隔离式固态继电器,TMUX6136PWR、TMUX1109PWR、TMUX1133PWR模拟开关与多路复用器(参数)

1、TPSI2140-Q1 是一款隔离式固态继电器&#xff0c;专为高电压汽车和工业应用而设计。 TPSI2140-Q1 与 TI 具有高可靠性的电容隔离技术和内部背对背 MOSFET 整合在一起&#xff0c;形成了一款完全集成式解决方案&#xff0c;无需次级侧电源。 该器件的初级侧仅由 9mA 的输入电…

Studio One 6.6.2 for Mac怎么激活,有Studio One 6激活码吗?

如果您是一名音乐制作人&#xff0c;您是否曾经为了寻找一个合适的音频工作站而苦恼过&#xff1f;Studio One 6 for Mac是一款非常适合您的MacBook的音频工作站。它可以帮助您轻松地录制、编辑、混音和发布您的音乐作品。 Studio One 6.6.2 for Mac具有直观的界面和强大的功能…

Zookeeper: 配置参数解读

Zookeeper中的配置文件zoo.cfg中参数含义解读如下&#xff1a; tickTime&#xff1a;通信心跳时间&#xff0c;Zookeeper服务器与客户端心跳时间&#xff0c;单位毫秒。 initLimit: LF初始通信时限 Leader和Follower初始连接时能容忍的最多心跳数。 syncLimit: LF同步通信时…

算法01 递推算法及相关问题详解【C++实现】

目录 递推的概念 训练&#xff1a;斐波那契数列 解析 参考代码 训练&#xff1a;上台阶 参考代码 训练&#xff1a;信封 解析 参考代码 递推的概念 递推是一种处理问题的重要方法。 递推通过对问题的分析&#xff0c;找到问题相邻项之间的关系&#xff08;递推式&a…

mongodb 集群安装

1. 配置域名 Server1&#xff1a; OS version: CentOS Linux release 8.5.2111 hostnamectl --static set-hostname mongo01 vi /etc/sysconfig/network # Created by anaconda hostnamemong01 echo "192.168.88.20 mong1 mongo01.com mongo02.com" >> /…

用GAN网络生成彩票号码

1. 前言 生成对抗网络&#xff08;GAN&#xff0c;Generative Adversarial Network&#xff09;是由Ian Goodfellow等人在2014年提出的一种深度学习模型&#xff0c;用于学习和生成与真实数据分布相似的数据。GAN由生成器&#xff08;Generator&#xff09;和判别器&#xff08…

Python编程环境搭建

简介&#xff1a; Python环境安装比较简单&#xff0c;无需安装其它依赖环境&#xff0c;主要步骤为&#xff1a; 1. 下载并安装Python对应版本解释器 2. 下载并安装一个ide编码工具 一、下载并安装Python解释器 1.1 下载 官网地址&#xff1a;Welcome to Python.org 选择…

STM32-CAN

一、CAN总线简介 1.1 CAN简介 CAN 是 Controller Area Network 的缩写&#xff08;以下称为 CAN&#xff09;&#xff0c;是 ISO 国际标准化的串行通信 协议。异步半双工。 ISO11898&#xff1a;123kbps~1Mbps。 ISO11519&#xff1a;125kbps 特点&#xff1a; 多主控制没…

Dify源码本地部署启动

背景 Dify是一个开源LLM应用程序开发平台。Dify的直观界面结合了人工智能工作流、RAG管道、代理功能、模型管理、可观察性功能等&#xff0c;让您快速从原型到生产。 Dify提供在线试用功能&#xff0c;可以直接在线体验其功能。同时也支持docker部署&#xff0c;源码部署等方…

【Vue】Pinia管理用户数据

Pinia管理用户数据 基本思想&#xff1a;Pinia负责用户数据相关的state和action&#xff0c;组件中只负责触发action函数并传递参数 步骤1&#xff1a;创建userStore 1-创建store/userStore.js import { loginAPI } from /apis/user export const useUserStore defineStore(…

ARP协议相关

把ip地址解析成mac地址这里的mac地址就是路由器的mac地址 免费ARP 源ip和目的ip都是一样的&#xff0c;那怎么让其他人更新arp表呢&#xff1f;&#xff1f; 是因为目标mac是全f&#xff0c;是一个广播报文 如果冲突就是ip一样但是mac又不一样 代理ARP pc1和pc4是在同一个子网…

算法训练营第六十天(延长12天添加图论) | LeetCode 647 回文子串、LeetCode 516 最长回文子序列

LeetCode 67 回文子串 思路很简单&#xff0c;每一个dp[i]等于dp[i-1]加上当前字符向前直到0各个长度字符串回文串个数即可 代码如下&#xff1a; class Solution {public boolean isValid(String s) {int l 0, r s.length() - 1;while (l < r) {if (s.charAt(l) ! s.ch…

谷歌企业开发者账号注册的常见问题及解决方法

今天跟大家分享一下注册谷歌开发者企业号的一些注意事项和干货&#xff0c;少走一些弯路。 首先&#xff0c;各位开发者朋友应该都知道&#xff0c;谷歌平台上有两种类型开发者账号&#xff1a;个人开发者账号和企业开发者账号。个人账号上架周期长&#xff0c;需要14天的封测&…

C#传值参数 -1值类型 -2引用类型

传值参数 -1值类型 -2引用类型 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; //传值参数-1、值类型 2、引用类型 namespace PamatetersExample {class Program{static void Main(string[] args){St…

2 选频网络

目录 选频网络 什么是选频网络 选频网络的分类 串联谐振回路 等效电路 阻抗特性 品质因素 电压谐振 广义失谐系数 谐振曲线&#xff08;幅频曲线&#xff09; 通频带 相频曲线 考虑信号源内阻与负载电阻 并联谐振回路 等效电路 导纳特性 品质因素 电流谐振…

C++11 move左值转化为右值

单纯的左值只能用左值引用和右值只能用右值引用有些局限&#xff0c;在一些情况下&#xff0c;我们也需要对左值去调用右值引用&#xff0c;从而实现将左值里的内容转移到右值中 标准定义&#xff1a; 功能就是将一个左值强制转化为右值&#xff0c;然后实现移动语义 注意&…

2024年7款硬盘恢复软件:即刻恢复硬盘删除的文件!

当文件被删除后&#xff0c;它并不是立即从硬盘中消失&#xff0c;而是被标记为“已删除”&#xff0c;等待垃圾回收处理。因此&#xff0c;在文件被删除后&#xff0c;有几种方法可以尝试恢复删除的数据。 以下是7款常用的数据恢复软件&#xff0c;以及它们的详细介绍&#xf…

Reactor 网络模型、Java代码实例

文章目录 1. 概述2. Reactor 单线程模型2.1 ByteBufferUtil2.2 服务端代码2.3 客户端2.4 运行截图 3. Reactor多线程模型3.1 服务端代码3.2 运行截图 4. 主从 Reactor多线程模型4.1 服务端代码4.2 运行截图 参考文献 1. 概述 在 I/O 多路复用的场景下&#xff0c;当有数据处于…