结构体详解-程序员宅基地

技术标签: c语言  

 前言:本章给大家详细介绍一下结构体的相关内容,结构体类型,定义和初始化,内存对齐等,让我们来了解一下吧

1.结构体的声明

结构:结构就是一些值的集合,这些值就是成员变量。

结构体的关键字struct

1.1一般的结构体声明

当我们想要描述一个学生,因为学生有很多的成员变量,比如姓名,年龄,这个时候我们就可以使用结构体来声明


	struct student
	{
		char name[20];//姓名
		int age;//年龄
		char sex[10];//性别
	}s;

接下来给大家介绍一下:

1.2匿名结构体  


	struct
	{
		char a[10];
		int b;
	}x;

就是在结构体声明的时候省去结构体标签 

1.3自引用结构体

结构体也是可以自己引用自己的


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

这样结构体就可以自己对自己引用了

1.4结构体的定义的初始化

#include<stdio.h>
struct student
{
	char name[20];//姓名
	int age;//年龄
}s1 = { "xiaoming",15 };
int main()
{
	struct student s2 = { "dazheng",30 };
	return 0;
}

接下来让我们分析一下:

 2.结构体成员访问

结构体成员访问有2种形式:

2.1结构体变量访问成员

通过操作符.进行访问,接受两个操作数

#include<stdio.h>
struct student
{
	char name[20];//姓名
	int age;//年龄
}s1 = { "xiaoming",15 };
int main()
{
	struct student s2 = { "dazheng",30 };
	printf("%d", s1.age);
	return 0;
}

s1.age就是访问s1当中的年龄成员

 2.2结构体指针访问指向变量的成员

#include<stdio.h>
struct student
{
	char name[20];
	int age;
}s1 = { "xiaoming",15 };
void print(struct student* p)
{
	printf("%s %d\n", p->name, p->age);
}
int main()
{
	struct student s2 = { "dazheng",30 };
	print(&s2);
	return 0;
}

3.结构体的内存对齐

我们已经了解了结构体的基本使用,接下来让我们了解一下结构体的大小

这里就有一个考点:结构体对齐

3.1对齐规则

首先我们要知道结构体的对齐规则:

1.第一个成员在与结构体变量偏移量为0的地址处

2.其他成员变量要对齐对齐数的整数倍的地址处

对齐数就是编译器默认的一个对齐数与该成员的较小值,VS中默认为8

比如说int类型占4个字节,vs默认为8,其较小值就是4,所以对齐数就是4

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

4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍,结构体的整体大小就是所有最大对齐数的整数倍

3.2列题理解

接下来让我们看一下例题进行理解

#include<stdio.h>
struct s1
{
	char c1;
	int i;
	char c2;
};
int main()
{
	printf("%d", sizeof(struct s1));
	return 0;
}

接下来给大家画图分析一下:

让我们看一下运行结果:

接下来我们看一下结构体的嵌套问题:

#include<stdio.h>
struct S3
{
	double d;
	char c;
	int i;
};
struct S4
{
	char c1;
	struct S3 s3;
	double d;
};
int main()
{
	printf("%d", sizeof(struct S4));
	return 0;
}

接下来给大家画图分析一下:

 运行结果:

3.3内存对齐的原因

当我们了解了对齐规则来给大家讲解一下为什么会有内存对齐

1.平台原因

我们使用的编译平台些许不同,不是所有的硬件平台都能访问任意地址上的任意数据的

2.性能原因

数据结构应该尽可能在自然边界对齐,为了访问未对齐的内存,处理器就需要访问两次,而访问对齐的内存,只需要一次访问,可以大大节省时间,结构体的内存对齐就是拿空间来换取时间的做法

注意:当我们设计结构体时,尽可能让占用空间小的成员集中在一起,这样既可以节省空间,也可以节省一定的时间

3.4修改默认对齐数

我们可以使用#pragma这个预处理指令

#pragma pack(1) //设置默认对齐数为1
#include<stdio.h>
struct s1
{
	char c1;  //1 1 1
	int i;	  //4 1 1
	char c2;  //1 1 1
};
int main()
{
	printf("%d", sizeof(struct s1));
	return 0;
}
#pragma pack()  //取消设置的默认对齐数

修改默认对齐数为1,内存就只占6个字节

当结构在对齐方式不太合适的时候,我们可以自己根据情况修改默认对齐数 

4.位段

4.1位段的介绍

1.位段的成员必须是 int  unsigned int  signed int

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


struct a
{
	int a : 2;
	int b : 3;
};

4.2位段的内存分配

#include<stdio.h>
struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 6;
};
int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;
	printf("%d", sizeof(struct S ));
	return 0;
}

我们通过这段代码来理解一下位段在内存中如何储存

接下来画图给大家分析一下:

 接下来我们再看一道例题

int main()
{
  unsigned char puc[4];
  struct tagPIM
  {
    unsigned char ucPim1;
    unsigned char ucData0 : 1;
    unsigned char ucData1 : 2;
    unsigned char ucData2 : 3;
  }*pstPimData;
  pstPimData = (struct tagPIM*)puc;
  memset(puc,0,4);
  pstPimData->ucPim1 = 2; 
  pstPimData->ucData0 = 3;
  pstPimData->ucData1 = 4;
  pstPimData->ucData2 = 5;
  printf("%02x %02x %02x %02x\n",puc[0], puc[1], puc[2], puc[3]);
  return 0;
}

 

相信大家对位段的计算有了一定的了解 

4.3位段的好处

 合理的使用位段可以大大的节省空间,更加合理的分配空间,节省空间

4.4位段的缺点(位段的跨平台问题)

1.int位段被当成是有符号还是无符号是不确定的

2.位段的最大数目不能确定

3.位段成员在内存中是从左向右分配,还是从右向左分配不确定(VS从右向左分配)

4.当一个结构包含两个位段,第二个位段的成员比较大,无法容纳在第一个位段时,是舍弃剩余位还是利用不确定

4.5位段的使用

当我们在网络上发送信息,是有网络协议的,下面是网络协议中,IP数据报的格式,可以看到这里很多只需要几个bit,所以使用位段可以大大的节省空间,可以让更加网络的畅通

 结语:

本章主要介绍了结构体的声明,成员访问,内存的对齐规则,以及位段,当我们了解这些可以对结构体有更好的认识,在今后可以更加合理的利用,欢迎大家评论,如有错误及时与我联系改正

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/unlockjy/article/details/137019319

智能推荐

解决win10/win8/8.1 64位操作系统MT65xx preloader线刷驱动无法安装_mt65驱动-程序员宅基地

文章浏览阅读1.3w次。转载自 http://www.miui.com/thread-2003672-1-1.html 当手机在刷错包或者误修改删除系统文件后会出现无法开机或者是移动定制(联通合约机)版想刷标准版,这时就会用到线刷,首先就是安装线刷驱动。 在XP和win7上线刷是比较方便的,用那个驱动自动安装版,直接就可以安装好,完成线刷。不过现在也有好多机友换成了win8/8.1系统,再使用这个_mt65驱动

SonarQube简介及客户端集成_sonar的客户端区别-程序员宅基地

文章浏览阅读1k次。SonarQube是一个代码质量管理平台,可以扫描监测代码并给出质量评价及修改建议,通过插件机制支持25+中开发语言,可以很容易与gradle\maven\jenkins等工具进行集成,是非常流行的代码质量管控平台。通CheckStyle、findbugs等工具定位不同,SonarQube定位于平台,有完善的管理机制及强大的管理页面,并通过插件支持checkstyle及findbugs等既有的流..._sonar的客户端区别

元学习系列(六):神经图灵机详细分析_神经图灵机方法改进-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏27次。神经图灵机是LSTM、GRU的改进版本,本质上依然包含一个外部记忆结构、可对记忆进行读写操作,主要针对读写操作进行了改进,或者说提出了一种新的读写操作思路。神经图灵机之所以叫这个名字是因为它通过深度学习模型模拟了图灵机,但是我觉得如果先去介绍图灵机的概念,就会搞得很混乱,所以这里主要从神经图灵机改进了LSTM的哪些方面入手进行讲解,同时,由于模型的结构比较复杂,为了让思路更清晰,这次也会分开几..._神经图灵机方法改进

【机器学习】机器学习模型迭代方法(Python)-程序员宅基地

文章浏览阅读2.8k次。一、模型迭代方法机器学习模型在实际应用的场景,通常要根据新增的数据下进行模型的迭代,常见的模型迭代方法有以下几种:1、全量数据重新训练一个模型,直接合并历史训练数据与新增的数据,模型直接离线学习全量数据,学习得到一个全新的模型。优缺点:这也是实际最为常见的模型迭代方式,通常模型效果也是最好的,但这样模型迭代比较耗时,资源耗费比较多,实时性较差,特别是在大数据场景更为困难;2、模型融合的方法,将旧模..._模型迭代

base64图片打成Zip包上传,以及服务端解压的简单实现_base64可以装换zip吗-程序员宅基地

文章浏览阅读2.3k次。1、前言上传图片一般采用异步上传的方式,但是异步上传带来不好的地方,就如果图片有改变或者删除,图片服务器端就会造成浪费。所以有时候就会和参数同步提交。笔者喜欢base64图片一起上传,但是图片过多时就会出现数据丢失等异常。因为tomcat的post请求默认是2M的长度限制。2、解决办法有两种:① 修改tomcat的servel.xml的配置文件,设置 maxPostSize=..._base64可以装换zip吗

Opencv自然场景文本识别系统(源码&教程)_opencv自然场景实时识别文字-程序员宅基地

文章浏览阅读1k次,点赞17次,收藏22次。Opencv自然场景文本识别系统(源码&教程)_opencv自然场景实时识别文字

随便推点

ESXi 快速复制虚拟机脚本_exsi6.7快速克隆centos-程序员宅基地

文章浏览阅读1.3k次。拷贝虚拟机文件时间比较长,因为虚拟机 flat 文件很大,所以要等。脚本完成后,以复制虚拟机文件夹。将以下脚本内容写入文件。_exsi6.7快速克隆centos

好友推荐—基于关系的java和spark代码实现_本关任务:使用 spark core 知识完成 " 好友推荐 " 的程序。-程序员宅基地

文章浏览阅读2k次。本文主要实现基于二度好友的推荐。数学公式参考于:http://blog.csdn.net/qq_14950717/article/details/52197565测试数据为自己随手画的关系图把图片整理成文本信息如下:a b c d e f yb c a f gc a b dd c a e h q re f h d af e a b gg h f bh e g i di j m n ..._本关任务:使用 spark core 知识完成 " 好友推荐 " 的程序。

南京大学-高级程序设计复习总结_南京大学高级程序设计-程序员宅基地

文章浏览阅读367次。南京大学高级程序设计期末复习总结,c++面向对象编程_南京大学高级程序设计

4.朴素贝叶斯分类器实现-matlab_朴素贝叶斯 matlab训练和测试输出-程序员宅基地

文章浏览阅读3.1k次,点赞2次,收藏12次。实现朴素贝叶斯分类器,并且根据李航《统计机器学习》第四章提供的数据训练与测试,结果与书中一致分别实现了朴素贝叶斯以及带有laplace平滑的朴素贝叶斯%书中例题实现朴素贝叶斯%特征1的取值集合A1=[1;2;3];%特征2的取值集合A2=[4;5;6];%S M LAValues={A1;A2};%Y的取值集合YValue=[-1;1];%数据集和T=[ 1,4,-1;..._朴素贝叶斯 matlab训练和测试输出

Markdown 文本换行_markdowntext 换行-程序员宅基地

文章浏览阅读1.6k次。Markdown 文本换行_markdowntext 换行

错误:0xC0000022 在运行 Microsoft Windows 非核心版本的计算机上,运行”slui.exe 0x2a 0xC0000022″以显示错误文本_错误: 0xc0000022 在运行 microsoft windows 非核心版本的计算机上,运行-程序员宅基地

文章浏览阅读6.7w次,点赞2次,收藏37次。win10 2016长期服务版激活错误解决方法:打开“注册表编辑器”;(Windows + R然后输入Regedit)修改SkipRearm的值为1:(在HKEY_LOCAL_MACHINE–》SOFTWARE–》Microsoft–》Windows NT–》CurrentVersion–》SoftwareProtectionPlatform里面,将SkipRearm的值修改为1)重..._错误: 0xc0000022 在运行 microsoft windows 非核心版本的计算机上,运行“slui.ex