【c语言】——结构体千字解读,看完你肯定不会有任何结构体的疑惑

这篇具有很好参考价值的文章主要介绍了【c语言】——结构体千字解读,看完你肯定不会有任何结构体的疑惑。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一.前言

在学习初期,我们接触了很多整型,浮点型,字符型等变量,其实结构体从整体上看和他们都差不多

其实现阶段对结构体有疑惑的无疑是

1.用的少,老是忘记怎么用 

2.对结构体的知识点不是很牢,经常弄混

第一点只能自己找题目练习,第二点不用担心,看完就可以豁然开朗了

 二.结构体的声明

首先先看结构体的模板:
struct stu
{
	member - list//成员列表
}variable - list;//变量列表,最后有一个分号不要忘记
例如表述一个学生
struct stu
{
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
};//分号不能丢

这里的变量其实有两种表示方法,比如可以想模板一样在后面加上变量名就可以

struct stu
{
	char name[20];
	int age;
	char sex[5];
}s,a,b;

因为之前说过他整体上和其他类型差不多,所以,也可以像其他类型一样在main函数里面创建

(细细品味这句话)

struct stu
{
	char name[20];
	int age;
	char sex[5];
}
int main()
{
	struct stu s;//创建结构体变量时,要把结构体的名字写全,不能只写一个struct

	return 0;
}
下面就到了容易弄混的地方了,也就是这里导致很多人忘记在结构体后面创建变量一会是变量,一会又是结构体的名字
typedef struct stu
{
	char name[20];
	int age;
	char sex[5];
}stu;//这里因为前面的typedef所以这个结构体的名字就变成了stu;
//后面在创建变量的时候就可以直接使用stu了;

以上就是结构体的基本声明和创建还有一些容易弄混的地方,其实结构体还有一些特殊的声明

结构体声明的时候可以 不完全声明,这种叫做匿名结构体类型
struct {//没有名字
	char name[20];
	int age;
	char sex[5];
}stu;

从这里你可以很清楚的看到这种声明方式和上面的不一样,既然不一样,那肯定是有区别的,

区别就在于这种匿名结构体只能使用一次,也就是说它只能在结构体后面创建变量,不能在main函数中重复创建,也就是说匿名结构体创建的变量,都在main函数之外,都是全局变量

还有就是如果你创建两个匿名结构体,编译器会认为他们是不同类型的,因为他们没有确定的类型名。但是这种匿名结构体也有好处,就是嵌套在结构体的结构体为匿名的时候,可以直接访问,这样比较方便,反之还需要特殊引用去处理,这里不展示了,知道就好

【c语言】——结构体千字解读,看完你肯定不会有任何结构体的疑惑,c语言,开发语言【c语言】——结构体千字解读,看完你肯定不会有任何结构体的疑惑,c语言,开发语言

三.结构体的自引用

 顾名思义,就是自己引用自己

但也没有我们想的那么简单,下面看一段代码思考一下就知道了

struct stu {
	int age;
	struct stu s;
};//思考这个结构体有多大?

 这个结构体会大到无穷,就感觉像一个无限的递归一样,所以是不合理的

正确的应该是把第二个元素换成指针形式,这样通过指针我们就知道这个结构体是多大了,

struct stu {
	int age;
	struct stu* next;
};

 这里用到了数据结构的知识,知道有这么回事就行了

上面说了结构体的大小问题,那么我们是怎么去计算结构体大小的呢?

四.结构体内存对齐

首先先看下面一段代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
struct stu {
	char b;
	int age;
	char a;
};
struct node {
	char a;
	char b;
	int age;
	
};
int main()
{
	cout << sizeof(struct stu) << endl;
	cout << sizeof(struct node);
}

计算的是他们的大小,可以先思考一下,他们的大小是否相同

【c语言】——结构体千字解读,看完你肯定不会有任何结构体的疑惑,c语言,开发语言

这么可以看到是不一样的,这是因为结构体有自己的内存对齐规则

  1.结构体的第一个成员对齐到和结构体变量的起始位置偏移量为0的地址处

  2.其他成员对齐到某个数字(对齐数)的整数倍处

对齐数=编译器默认的一个对齐数和变量本身大小的较小值

  3.结构体的总大小为最大对齐数的整数倍

  4.如果嵌套了结构体的时候,结构体的整体大小就是所以最大对齐数的整数倍

很多人应该看完,还是一头雾水,就用上面的例子来解释

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
struct stu {
	char b;//大小为1,默认对齐数是8(编译器不一样,默认对齐数就不一样),1<8那么1是他的对齐数
	int age;//同理,他的对齐数是4;
	char a;//对齐数是1;
};
//那么从第一个规则我们可以知道,第一个变量是在偏移量为0处也就是第一个位置,占一个字节
//因为第二个变量对齐数是4,(2,3不是4的整数倍,但4是)所以第二个变量从第四给字节开始往后占4个字节
//第三个变量对齐数是1,第二个变量以后来到了第8个字节位置,所以又8是1的整数倍,所以把它放进去
//最后他们三个变量的最大对齐数是4,所以看9是否是4的整数倍(因为从0开始到8一共9个字节),是,那么它的大小就是9,不是,则往后找,直到找到4的倍数位置,所以这里找到12;




struct node {
	char a;
	char b;
	int age;
	
};
//这里的计算可以照猫画虎,很容易就得出它的大小为8;
int main()
{
	cout << sizeof(struct stu) << endl;
	cout << sizeof(struct node);
}

对齐规则你可以用不到,但是你不能不知道,这里只是用文字进行描述,没有画图,如果有什么疑问可以在评论区发言

五. 结构体传参

结构体传参可以分为两种,结构体传参和结构体地址传参

 虽然分为两种方式,但是大多都是用的结构体地址传参,因为用结构体传参参数压栈的系统开销比较大,所以一般不用第一种

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
struct stu {
	int age;
	char name[20];
};
void print(struct stu* p) {
	cout << p->age;//指针用->,变量用.
}
//void print(struct stu p){
cout<<p.age;
}
int main()
{
	struct stu s = { 20,"sdadasd" };
	print(&s);
//print(s);
	return 0;
}

六.结构体实现位段

1.位段的成员必须是unsigned int ,int ,signed int或者是char类型

2.位段的成员名后面一个冒号和一个数字

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
struct stu {
//开始的时候会创建一个字节的空间,然后放进去,如果不够再创建一个字节
	int a : 2;//这里的数字代表2位二进制位,下面同理
	int b : 5;
	int c : 10;
	int d : 30;
};
int main()
{
	struct stu s = { 0 };
	s.a = 10;//转化位二进制,然后放进开辟的空间里面去,可能空间不够会有一部分截断
	s.b = 12;
	s.c = 3;
	s.d = 4;
	return 0;
}

为什么要有位端呢,其实它的作用就是节省空间,但是它也有弊端,就是不能跨平台而且涉及了很多不确定的因素。

这里还有一个点就是位段的几个成员是共用一个字节的,所以我们在输入的时候,直接用scanf取地址输入是不行的,因为内存中分配一个地址,一个字节内部的bit位是没有地址的。

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
struct stu {
	int a : 2;
	int b : 5;
	int c : 10;
	int d : 30;
};
int main()
{
	struct stu s = { 0 };
	scanf("%d". & s.a);//错误
	
//正确
	int x;
	scanf("%d", &x);
	s.a = x;
	return 0;
}

如果你看到这里,那么相信你一定对结构体有一定的了解和理解了,下面就是多去练习,发现问题

希望这篇文章对大家有帮助,如果有任何疑问可以发在评论区

后面会更新动态内存和文件的相关知识,请持续关注我文章来源地址https://www.toymoban.com/news/detail-837937.html

到了这里,关于【c语言】——结构体千字解读,看完你肯定不会有任何结构体的疑惑的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MySQL的面试题讲解看完肯定对你有帮助!!

    InnoDB和MyISAM是MySQL数据库常见的两种存储引擎,它们在功能和性能方面有一些重要区别:         1.事务支持 :InnoDB是一个支持事务处理的存储引擎,它使用了ACID(原子性、一致性、隔离性和持久性)特性来确保数据的完整性。而MyISAM不支持事务,它执行的是自动提交模

    2024年02月12日
    浏览(26)
  • python之django框架入门,看完你就会

    目录 1.创建Django项目  2.创建Django应用  3.定义ORM模型 4.创建并执行数据库迁移 5.定义视图函数 6.定义URL路由 7.编写模板 Django是一个基于Python的Web框架,它旨在提供开发人员一个高效而且富有灵活性的工具集。它包含了一套完整的组件,涵盖了从路由、视图、模板、表单到O

    2024年02月09日
    浏览(59)
  • AI绘画是什么软件?看完你就知道了

    你们知道吗?AI绘画软件其实是通过AI技术,绘画出不同风格的画,让大家都可以根据自己的需求画出漂亮的图片;它还可以描述出自己想象的场景,并添加一张参考图,随后便自动生成画作,那么你们知道智能AI绘画免费软件有哪些吗?如果还不是很了解的话,那就跟着我一

    2024年02月11日
    浏览(57)
  • 手机扫描怎么做成文档?看完你就学会操作了

    相信很多职场人在办公的时候,经常会遇到大量的文件需要处理,其中一部分可能是纸质版的文件。但为了方便进行编辑,大家需要可以借助一些扫描软件对纸质版文件进行扫描,但是还有一部分小伙伴可能还不知道应该怎么进行操作。 今天就给大家带来三种较为简单的方法

    2024年02月08日
    浏览(51)
  • 电脑技巧:宽带怎么设置教程笔记,看完你就会了

    宽带的设置是指将计算机连接到互联网的过程。一般来说,宽带的设置是非常简单的,只需要按照提供商的要求,正确地连接硬件和软件就可以了。下面将详细介绍如何设置宽带。 硬件设置:首先,需要连接计算机和调制解调器,以及路由器(如果有的话)。通常,宽带提供

    2024年02月11日
    浏览(47)
  • ai绘画图片美女怎么画?看完你就知道了

    大家在刚开始接触文生图的AI绘画的时候,是不是会因为在输入描述词时不知道应该如何描述,而导致生成的图片都比较简单或者混乱,不符合自己的预期。 其实,我刚接触AI绘图也是这样的,不过经过我的探索,我用AI做的图越来越漂亮了,给大家欣赏一下。 那么大家想知

    2024年02月14日
    浏览(46)
  • SpringBoot整合OAuth2.0看完你就会了!

    OAuth 2.0是一种开放的授权协议,它允许用户授权第三方应用访问其账户(或资源),而无需共享其用户账户凭据。在Spring Boot中,我们可以使用Spring Security的OAuth2.0模块来实现授权验证。 好了到此为止,以上就是springboot整合ouath2.0的主要代码啦,欢迎大家在评论区留言讨论!

    2024年02月06日
    浏览(45)
  • 月薪6000在中国什么水平?看完你就不焦虑了

    今天刷到一个很扎心的问题:你对自己现在的收入满意吗? 多数人都是不假思索地反问:“怎么会满意……” 都说挣钱够用就行,谁又真正满意过。 镜头前的主播抱怨忙,却偷偷年收百万,00后副业月入10万,连知根知底的发小,也突然月入过万。 而你拼命不比谁少, 跑进

    2023年04月22日
    浏览(46)
  • 无线路由器为什么需要重启 看完你就知道

    无线路由器已经成为每个家庭中不可或缺的网络设备。使用WiFi网络,无论是上网刷微博,还是在线追剧,亦或是进行在线游戏,经常卡顿的现象是最让人受不了的。有时候WiFi连接不佳,拍两下路由器是没有效果的。我们会重启无线路由器,重启后明显会感觉的网络变得流畅

    2024年02月05日
    浏览(52)
  • 【Unity】Time.deltaTime有什么用?看完你就明白

    大多数刚开始使用 Unity 的人(包括我),都会对 Time.deltaTime 感到迷惑。 看完本文,你就会明白 Time.deltaTime的定义及作用。 根据定义, Time.deltaTime是每一帧之间的时间间隔 (以秒为单位)。 这有助于我们使游戏与帧数无关,也就是说,无论 fps 是多少,游戏都将以相同的速

    2024年02月16日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包