当前位置: 首页 > news >正文

【C语言】详解结构体(上)

文章目录

  • 前言
  • 1. 结构体类型的含义
  • 2.结构体的声明
    • 2.1 结构体声明的语法
    • 2.2 结构体变量的创建和初始化
  • 3.结构体的特殊声明
  • 4. 结构体的自引用
  • 5.小结

前言

C语言的数据类型分为内置数据类型和自定义的数据类型。所谓的内置的数据类型可以认为是C语言自带的数据类型(char、int、float、double、bool),而自定义的数据类型(数组、结构体、联合体和枚举)中的结构体类型就是本文所要分享给大家的。

1. 结构体类型的含义

我们在正式学习结构体之前,得先了解一下结构体到底是个什么东西?
有句古话说的好:知己知彼,方能百战不殆。
我们想要学好结构体,就必须得对它有一定的了解。为了让大家能够更好的学习结构体,这里就先引入我们之前学过的数组的一些知识。

我们都是知道,数组里面的元素都是相同类型的,并且它们在内存空间中是连续存放的。那这时我们就会有这么一个疑惑?C语言有没有一种数据类型能够存放一次性包括多种不同的数据类型。答案是有的,那就是我们本讲的主角——结构体

总而言之,当我们在编程时遇到了一个个体,这个个体包含着许多不同的属性,一个一个定义就显得过于繁琐且不方便,那么结构体就刚好适应这种场景的需求。

2.结构体的声明

在讲完结构体的含义之后,那我们该如何去定义一个结构体呢?

2.1 结构体声明的语法

struct tag
{member-list; 
}varible-list;
符号含义
tag标签,可以理解为结构体名字
member-list成员列表,之后我们就是在这个花括号内来写我们想要存储的变量
varible-list变量列表,这个就是我们利用结构体创建之后直接给结构体变量的名称

注意:结构体名称和结构体变量名称是两个不一样的东西,不要给混淆了

例如:我们描述一个学生

struct Student
{char name[20];//姓名int age;//年龄char sex[5];//性别char id[20];//学号
}; //这里有个分号,一定不要忘记写了

2.2 结构体变量的创建和初始化

struct S
{char c;int i;double d;
};struct Stu
{char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号
};int main()
{//按照结构体的成员顺序进行赋值struct Stu s1 = { "张三",22,"男","123456789" };printf("name: %s\n",s1.name);printf("age: %d\n", s1.age);printf("sex: %s\n", s1.sex);printf("id: %s\n", s1.id);printf("\n");//按照知道指定的顺序赋值struct Stu s2 = { .age = 18,.name = "梨花",.id = "563217485",.sex = "女"};printf("name: %s\n", s2.name);printf("age: %d\n", s2.age);printf("sex: %s\n", s2.sex);printf("id: %s\n", s2.id);return 0;
}

结果演示
除了上述在main函数内创建结构体变量的方式之外,我们还可以在面函数外面创建结构体变量,如果是这样做的话,这个变量就相当于全局变量了。

//方法一
struct Stu
{char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号
}s1,s2; //变量列表//方法二
struct Stu s3;int main()
{...
}

3.结构体的特殊声明

在声明结构体时,我们也可以做到不完全声明。具体一点来讲,就是不给结构体名字。
我们将这种结构体称为“匿名结构体
比如:

//匿名结构体类型
struct
{int i;char ch;double d;
}s;
struct
{int i;char ch;double d;
}* ps;

可以观察到,匿名结构体在声明时,的确出现了省略标签(tag)的现象。

不过需要注意的是,匿名结构体只能用一次。这里的“用一次”也就是说该匿名结构体在本声明之初就应该一次性在变量列表中创建好所有变量的名称,等到脱离了匿名结构体的声明后,就再也没有办法创建一个新的结构体变量了。

那么我现在有个问题:

ps = &s; //这样写可以吗?

乍一看,好像确实没有什么问题啊!ps这个结构体指针所指向的结构体与结构体变量s里面的成员变量是一摸一样的。可事实真的如此吗?

错误警告

警告信息为:“=”: 从“*”“*”的类型不兼容
也就是说ps所指向的结构体与变量s所代表的结构体不属于同一个结构体类型,尽管它们里面成员一模一样

为此,我们总结一下匿名结构体使用的注意事项:

  1. 匿名结构体只能使用一次
  2. 即使两个甚至是多个匿名结构体里面的成员列表的内容是一摸一样的,编译器也会把这些结构体视作不同类型的结构体变量

4. 结构体的自引用

在结构体包含一个类型为改结构体本身的成员是否可以呢?
答案是肯定的,不过有一定的语法规则。为什么会这样说呢?请看下面的代码:

//根据上面的意思,我们可以写出以下代码:
struct Node
{int data;struct Node next;
};

上面的代码合理吗?如果合理的话,请告诉我sizeof(struct Node)的值为多少?
显然,问到这里,你就会发现,这个结构体这样声明确实有点问题。这个结构体的声明给我们一种陷入了死循环的感觉,而这个结构体的大小就为无穷大。

正确子引用的方式:

struct Node
{int data;struct Node* next;
};

我们用一个指向该结构体的指针作为该成员变量,这样做不仅可以知道该结构体的大小,还可以利用该指针访问其内部的数据,一举两得。

例外,我们还需要注意一种极其容易出现错误的写法:
我们再利用typedef给结构体重命名时:

typedef struct Node
{int data;Node* next;
}Node;

上述写法可行吗?
错误示范
原因是:编译器是从上往下来执行代码的,当执行到 Node* next 这条语句时,编译器由于还未完全读到typedef的所有语句,因此就将Node视作未定义的标识符。

正确的写法是:

typedef struct Node
{int data;struct Node* next;
}Node;

5.小结

在本文中,我想告诉大家的是:结构体的用途、结构体的声明、结构体的变量的创建及初始化还有结构体的自引用。内容不是很多,希望读者们能好好消化理解。

最后,如果觉得本文写的还不错的话,希望可以给偶带上个赞👍,阿里嘎多❤️❤️❤️。
让我们在详解结构体(下)这个篇章再见!!!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 通过Dockerfile构建镜像
  • 用HTML和CSS实现提示工具(tooltip)及HTML元素的定位
  • zookeeper+kafka消息队列群集部署
  • 分布式 I/O 系统Modbus TCP 耦合器BL200
  • pytorch中一些最基本函数和类
  • 集群架构-web服务器(接入负载均衡+数据库+会话保持redis)--15454核心配置详解
  • 华为USG6000V防火墙安全策略用户认证
  • 01.Verilog基础语法
  • js中scrollIntoView第一次不生效,第二次生效
  • Linux C++ 055-设计模式之状态模式
  • React 的生命周期方法有哪些?
  • [论文笔记]构建基于RAG聊天机器人的要素
  • pycharm2020 相比pycarm2017更新内容
  • redis安装,启动客户端、验证(redis第一次作业)
  • 深入Laravel的魔法核心:依赖注入的工作原理
  • ES6指北【2】—— 箭头函数
  • @jsonView过滤属性
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • Git初体验
  • Laravel 中的一个后期静态绑定
  • Linux各目录及每个目录的详细介绍
  • rabbitmq延迟消息示例
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • Tornado学习笔记(1)
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • Web设计流程优化:网页效果图设计新思路
  • XML已死 ?
  • 记一次删除Git记录中的大文件的过程
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 批量截取pdf文件
  • 前端临床手札——文件上传
  • 让你的分享飞起来——极光推出社会化分享组件
  • 深度学习入门:10门免费线上课程推荐
  • 数组大概知多少
  • 它承受着该等级不该有的简单, leetcode 564 寻找最近的回文数
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • 容器镜像
  • ​猴子吃桃问题:每天都吃了前一天剩下的一半多一个。
  • #include<初见C语言之指针(5)>
  • (42)STM32——LCD显示屏实验笔记
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (Redis使用系列) Springboot 整合Redisson 实现分布式锁 七
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (动态规划)5. 最长回文子串 java解决
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (转)ORM
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • (转)大型网站的系统架构
  • (转)视频码率,帧率和分辨率的联系与区别
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .NET 使用 XPath 来读写 XML 文件