结构体相关知识

news2024/11/18 2:45:54

结构体的概念

结构体说直白点就是自定义类型,c语言有很多内置的类型比如char,int,double等,而结构体就是我们自己命名的一种类型。

区别在于内置类型大多都是单一描述的类型,比如 char studentname='wangwu',只能描述一种类型。学生的属性有很多,比如char 类型的名字,int 类型的学号,double类型的分数。当然你也可以挨个去定义,比如 char name[]="wangwu",int sno=2425678,double scole=85.6;这样只能表示一个学生,如果再来一个学生zhangsan是不是又得写三行

但是这样就显得很麻烦,而为了解决这个问题,c语言就增加了结构体这种自定义数据类型。

总得来说,对于内置类型,结构体有两个不同,一.是可以自定义类型的。二.可以包含多个类型的数据

一个简单的结构体例子:学生结构体

struct student 
{
  char name[20];
   int sno;
   int age;
   int sex;
   double scole;
};

struct  标签(随便起个名字)

{

    member-list;成员列表

}variable-list;(变量列表)这里有没有变量列表无所谓,但是分号不能少

结构体的初始化

第一种主函数内全局变量定义初始化

#include<stdio.h>
struct student
{
	char name[20];
	int sno;
	int age;
	const char*sex;
	double scole;
};
int main()
{
	struct student student1={ "zhangsan",20230917,20,"男",98};
}

 这种形式必须一一对应,顺续不能变,数量也不能少

第二种初始化方法,指定顺序初始化,这种类型可以不按顺序来访问,直接点符号访问(请不要在不支持C99或更高版本的C++编译器.cpp源文件上用这个,会报错)

#include<stdio.h>
struct stu
{
	char name[20]; //名字
	int age; //年龄
	float score;
};
int main()
{
	struct stu s5 = { .score = 98.5f,.name = "hehe",.age = 100.0f };//想要先初始化什么直接用点.操作符就行了
}

第三种全局变量初始化方式,直接在结构体末尾使用
  

#include<stdio.h>
struct stu
{
	char name[20]; //名字
	int age; //年龄
	float score;
}s5 = { .score = 98.5f,.name = "hehe",.age = 100.0f }, s6 = {"wangwu",20,96};//不用加struct stu的头缀了,同样可以用点操作符改变顺序
int main()
{
	return 0;
}

结构体的类型

char a类型是char,int a的类型是int

上面的学生结构体,它的类型不是stu,而是struct stu。

#include<stdio.h>
struct stu
{
	char name[20]; //名字
	int age; //年龄
	float score;
}student;

上面代码的student是类型名吗,其实不是,这个结构体类型依旧是struct stu,而student是变量名

typedef struct DNode
{ 
  Elemtype data;
  struct DNode * prior;
  struct DNode * next; 
}DLinkNode;

上面代码是数据结构中常用的结构体表现形式,此时这个结构体可以说类型是DLinkNode

typedef关键字可以给类型起一个别名,比如typedef char Elemtype就是把char类型起了一个别名Elemtype,此时Elemtype就等价char

同样 上述代码中DLinkDode也等价于struct DNode 

结构体变量的访问

#include<stdio.h>
struct student
{
	char name[20];
	int sno;
	int age;
	const char*sex;
	double scole;
};
int main()
{
	struct student student1={ "zhangsan",20230917,20,"男",98};
}

这个结构体已经初始化了student1,如果要求打印出来该怎么操作呢

1.点(.)操作符直接访问

#include<stdio.h>
struct student
{
	char name[20];
	int sno;
	int age;
	const char* sex;
	double scole;
};
int main()
{
	struct student student1 = { "zhangsan",20230917,20,"男",98 };
	printf("名字:%s 学号:%d 年龄:%d 性别:%s 分数:%.2lf", student1.name, student1.sno, student1.age, student1.sex, student1.scole);
}

需要注意的是,此时打印是不需要加上struct的,student1仅仅起一个标识作用

举个例子,char i=5;肯定是printf("%c",i),而不是printf("%c",char i);

2.结构体成员的间接访问(结构体指针访问)

#include <stdio.h>
struct student
{
	char name[20];
	int sno;
	int age;
	const char* sex;
	double scole;
};
int main()
{
	struct student student1 = { "zhangsan",20230917,20,"男",98.5 };
	struct student* ptr = &student1;
	printf("%s %d %d %s %.1f\n", ptr->name, ptr->sno, ptr->age, ptr->sex, ptr->scole);
	printf("%s %d %d %s %.1f\n", student1.name, student1.sno, student1.age, student1.sex, student1.scole);
}

 ptr->name 不是地址或指针,而是通过指针 ptr 访问结构体中的成员变量 student1中的name,就等价于student1.name

其实也可以等价于(*ptr).name,ptr保存的是变量student1的地址,ptr 存储的是结构体的地址,通过解引用 ptr,我们可以获取结构体的内容,进而访问结构体变量student1的成员变量 name。

既然是解引用,那能不能改变值,数组里解引用然后赋值是可以改变原来的值的

直接写成解引用的形式然后赋值也是可以改变值的 

结构体嵌套

 结构体嵌套初始化

直接在最外层结构体那里一起初始化就行,大圈套小圈而已

嵌套结构体的访问

 点操作符直接访问

先用点操作符找到外层结构体Node的里层结构体变量p,然后p通过点操作符去访问p自己里面的内容x,y

结构体指针访问 

可不要用ptr->p->x去访问,用箭头去访问的前提是它是个指针,可是这里p可不是指针变量 

结构体大小(内存对齐)

如果求一个整型数据的大小,sizeof(int),它的结果是4,求一个字符char的字节大小,它的结果是1。可是结构体里面有多个成员,各个成员的类型也不完全就是相同的,sizeof结构体的大小是多少呢

示例

#include<stdio.h>
struct student
{
	char name[5];
	int sno;
	int age;
	double scole;
};
int main()
{
	int ret=sizeof(struct student);
	printf("%d", ret);
}

上面那个结构体按照正常的思维存,应该是如下图所示先存char数组的5个字节,然后两个int共8个字节,再然后double类型8个字节,总共21个字节

 然而运行起来实际结果是24

0到23正好24个字节,所以结果是24,int name上面编号6和7虽然没存任何东西,但是计算大小还是要计算进来的。

结构体内存对齐的规则

1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处
2.其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。
对⻬数=编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。
VS 编译器中默认的值为 8 
Linux中gcc没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩
3.结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的
整数倍。

拿上面那个示例总结一下,第一个结构体变量char name[5]起始位置直接默认从0开始就行,剩下的都要去找默认对齐数的倍数开始存。

name存完了后,要开始处理int sno,VS编译器中默认的对齐数是8,而此时int类型是4个字节,它比给的默认值还小,所以对齐数变为4,要去找4的倍数作为int name存储的起点。找下一个成员int age的存储的起点方法与int name类似

最后一个成员double,它的字节大小为8,与默认对齐数相等,所以对齐数就为8。找8的倍数作为doubie存储的起点,所以就是16了。

规则3是什么意思呢,比如说我最后22个字节就存储完了,但是最大对齐数的是8,所以我最后的结果也应该是8的倍数24,而不是22

再来一个示例

#include<stdio.h>
struct student
{
	
	int sno;
	char name[9];
	int age;
	double scole;
};
int main()
{
	int ret=sizeof(struct student);
	printf("%d", ret);
}

这个示例中int sno 虽然对齐数是4,但是第一个结构体成员默认从0作为起点。char name[9]总字节是9,而VS编译器默认对齐数是8,所以最小对齐数是8,应该去找8的倍数当作char name[9]的起点

嵌套结构体的大小(嵌套结构体的内存对齐)

如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构
体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。

#include<stdio.h>
struct s3
{ 
	double d;
	char c;
	int i;
};
struct s4
{
	char c1;
	struct s3 student3;
	double d;
};
int main()
{
	printf("%d\n", sizeof(struct s4));
};

 

要计算嵌套结构体s4的大小,要先计算出被嵌套结构体s3的大小,s3的大小如上图所示为16

s4第一个成员char c1默认存储的起点从0开始,不用考虑。那么第二个成员struct s3 student3从哪里开始呢.一般来讲判断存储的起点要找对齐数,而嵌套结构体对齐数就等于它里面成员最大对齐数。比如s3 它的最大对齐数是double是8,所以整个嵌套结构体s3存储起点要找8的倍数。s4的内存图示如下

0到31正好32个字节存完,要求整个结构体的大小,要求是最后结果是最大对齐数的倍数,而嵌套结构体要把里面的最大对齐数加入比较。s3里面最大对齐数是8,s4里还有一个double类型,所以最大对齐数应该是8的倍数。而32是8的倍数,所以结果是32

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 HTML 地标角色提高可访问性

请务必确保所有用户都可以访问您的网站&#xff0c;包括使用屏幕阅读器等辅助技术的用户。 一种方法是使用 ARIA 地标角色来帮助屏幕阅读器用户轻松浏览您的网站。使用地标角色还有其他好处&#xff0c;例如改进 HTML 的语义并更轻松地设置网站样式。在这篇博文中&#xff0c;我…

小米手机锁屏时间设置为永不休眠_手机不息屏_保持亮屏

环境&#xff1a;打开手机自带的锁屏时间设置发现没有 永不息屏的选项 原因&#xff1a;采用了三星OLED屏幕&#xff0c;所以根据OLED屏幕特性&#xff0c;这个是为了防止烧屏而特意设计的。非OLED机型支持设置“永不” 解决方案1&#xff1a;原生系统是支持永不锁屏的&#…

Java程序编写(上)

HelloWorld 1 创建一个以java为后缀名的文件 编写代码 public class Hello {public static void main(String[] args) {System.out.println("Hello, World!");} }其中&#xff0c;psvm是下述代码的缩写&#xff1a; public static void main(String[] args) sout是…

无人机语音中继电台 U-ATC118

简介 甚高频无线电中继通讯系统使用经过适航认证的机载电台连接数字网络传输模块&#xff0c;通过网络远程控制无缝实现无人机操作员与塔台直接语音通话。无人机操作员可以从地面控制站远程操作机载电台进行频率切换、静噪开关、PTT按钮&#xff0c;电台虚拟面板与真实面板布局…

C语言定长数组 变长数组 柔性数组

C语言定长数组 变长数组 柔性数组 文章目录 C语言定长数组 变长数组 柔性数组1. 定长数组2. 变长数组3. 柔性数组3.1 结构体的大小3.2 柔性数组的使用 1. 定长数组 在C99标准之前&#xff0c;C语言在创建数组的时候&#xff0c;数组的大小只能使用常量&#xff0c;常量表达式来…

CPU的三大调度

计算机系统中的调度可以分为不同层次&#xff0c;包括作业调度、内存调度和进程调度。这三种调度分别负责管理和优化计算机系统中不同层次的资源分配和执行顺序。 高级调度&#xff1a;作业调度&#xff08;Job Scheduling&#xff09;&#xff1a; 作业调度是指对提交到计算…

国产Type-C PD芯片—接口快充取电芯片

常用USB PDTYPE-C受电端&#xff0c;即设备端协议IC芯片&#xff08;PD Sink&#xff0c;也叫PD诱骗芯片&#xff09;&#xff0c;诱导取电芯片。 产品介绍 LDR6328: ◇ 采用 SOP-8 封装 ◇ 兼容 USB PD 3.0 规范&#xff0c;支持 USB PD 2.0 ◇ 兼容 QC 3.0 规范&#x…

Python绘制多分类ROC曲线

目录 1 数据集介绍 1.1 数据集简介 1.2 数据预处理 2随机森林分类 2.1 数据加载 2.2 参数寻优 2.3 模型训练与评估 3 绘制十分类ROC曲线 第一步&#xff0c;计算每个分类的预测结果概率 第二步&#xff0c;画图数据准备 第三步&#xff0c;绘制十分类ROC曲线 1 数据集…

TailwindCSS 如何设置 placeholder 的样式

前言 placeholder 在前端多用于 input、textarea 等任何输入或者文本区域的标签&#xff0c;它用户在用户输入内容之前显示一些提示。浏览器自带的 placeholder 样式可能不符合设计规范&#xff0c;此时就需要通过 css 进行样式美化。 当项目中使用 TailwindCSS 处理样式时&a…

手把手教你使用axure9画出图书出借的功能界面(原型模型)从0实现图书借阅界面

问题 设计图书出借的功能界面&#xff0c;并使用axure画出界面原型&#xff08;pc端或移动端都可以&#xff09;。就你的设计&#xff0c;你觉得有哪些方面需要跟用户沟通确认&#xff1f; 一、登录界面 1.先将图片背景改成灰色 2.插入文本框 3.插入文字&#xff0c;输入图书…

物联网第十四周总结

本周任务 消息转换器 PostgreSQL学习&#xff0c;JetLinks配置PostgreSQL 问题与总结 JetLinks配置PostgreSQL的时候&#xff0c;启动报错 2023-12-08 09:34:30.478 ERROR 19028 --- [actor-tcp-nio-1] o.h.e.r.e.r.r.R2dbcReactiveSqlExecutor : > Error: c…

Elasticsearch 8.9 refresh刷Es缓冲区的数据到Lucene,更新segemnt,使数据可见

一、相关API的handler1、接受HTTP请求的hander(RestRefreshAction)2、往数据节点发送刷新请求的action(TransportRefreshAction)3、数据节点接收主节点refresh传输的action(TransportShardRefreshAction) 二、在IndexShard执行refresh操作1、根据入参决定是使用lucene提供的阻塞…

Http请求(bug)——路径变量传参遇到特殊符号的问题 URL中的#,?,符号作用

前言 本篇博客分析路径变量传参遇到特殊符号的问题&#xff0c;阐述了URL中的#&#xff0c;&#xff1f;&#xff0c;&符号作用。 目录 前言引出路径变量传参遇到特殊符号的问题问题描述问题分析 URL中的 #&#xff0c;&#xff1f;&#xff0c;&符号的作用URL中# 的作…

【探索Linux】—— 强大的命令行工具 P.21(多线程 | 线程同步 | 条件变量 | 线程安全)

阅读导航 引言一、线程同步1. 竞态条件的概念2. 线程同步的概念 二、条件变量1. 条件变量函数⭕使用前提&#xff08;1&#xff09;初始化条件变量&#xff08;2&#xff09;等待条件满足&#xff08;3&#xff09;唤醒等待pthread_cond_broadcast()pthread_cond_signal() &…

Qexo博客后台管理部署

Qexo博客后台管理部署 个人主页 个人博客 参考文档 https://www.oplog.cn/qexo/本地部署 采用本地Docker部署管理本地Hexo 下载代码包 若无法下载使用科学工具下载到本地在上传到服务器 wget https://github.com/Qexo/Qexo/archive/refs/tags/3.0.1.zip# 解压 unzip Qexo…

SQL命令---修改字段的排列位置

介绍 使用sql语句表字段的排列顺序。 命令 alter table 表名 modify 字段名1 数据类型 first|after 字段名2;例子 将a表中的age字段改为表的第一个字段。 alter table a modify age int(12) first;下面是执行命令后的表结构&#xff1a; 将a表中的age字段放到name字段之…

【linux】查看CPU和内存信息

之前咱们一起学习了查看内存的和CPU的命令。 ​mpstat &#xff1a; 【linux】 mpstat 使用 uptime&#xff1a;【Linux】 uptime命令使用 CPU的使用率&#xff1a;【linux】查看CPU的使用率 nmon &#xff1a;【linux】nmon 工具使用 htop &#xff1a;【linux】htop 命令…

学习Linux(2)-学习Linux命令

Linux目录结构 Linux目录结构-菜鸟教程 /bin&#xff1a;bin 是 Binaries (二进制文件) 的缩写, 这个目录存放着最经常使用的命令。 /boot&#xff1a;这里存放的是启动 Linux 时使用的一些核心文件&#xff0c;包括一些连接文件以及镜像文件。 /dev &#xff1a;dev 是 De…

Cocos Creator:创建棋盘

Cocos Creator&#xff1a;创建棋盘 创建地图三部曲&#xff1a;1. 创建layout组件2. 创建预制体Prefab&#xff0c;做好精灵贴图&#xff1a;3. 创建脚本LayoutSprite.ts收尾工作&#xff1a; 创建地图三部曲&#xff1a; 1. 创建layout组件 使用layout进行布局&#xff0c;…

数据表记录的操作

一、数据添加 1、打开SSMS&#xff0c;附加数据库&#xff08;数据库文件在自己的文件夹下面&#xff09;&#xff0c;并进行下面的设置&#xff1a; &#xff08;1&#xff09;设置“部门信息”表中的“编号”为主键&#xff08;SSMS&#xff09; 首先建立好所需的数据库库…