C语言-结构体-详解

博客主页:【夜泉_ly】
本文专栏:【C语言】
欢迎点赞👍收藏⭐关注❤️

C语言-结构体-详解

  • 1.前言
  • 2.结构体类型
    • 2.1声明
    • 2.2变量的创建与初始化
    • 2.3访问
    • 2.4匿名结构体类型
  • 3.结构体内存对齐
    • 3.1对齐规则
    • 3.2示例

1.前言

在C语言中,除了整型、浮点型等给定的类型外,还有很多自定义类型,结构体就是其中之一。
结构体十分重要,想要学好数据结构,必须掌握指针、结构体和动态内存管理。
本篇,我将详细介绍C语言中的结构体。

2.结构体类型

结构体作为C语言的一种重要的数据类型,其特点是由一组数据组合而成,且这些数据的类型可以不同。

2.1声明

基本框架:

struct tag
{member-list;
}variable-list;

其中,tag为该结构体的名字,member-list为成员列表,variable-list为创建变量的列表。
例如:

struct student
{char name[20];int age;int tele;
}s1,s2;

为了存储一个学生的信息,需要存储姓名、年龄、电话等等内容,这些内容的数据类型显然不同,因此,可以用结构体存储:

struct student

这里定义了一个结构体类型struct student,代表该结构体类型用于存储学生信息。
在这之后:

{char name[20];int age;int tele;
}

这里的namenametele称为结构体的成员,共同组成成员列表。
最后:

s1,s2;

这里使用结构体类型创建了两个变量s1s2,代表学生一和学生二。
当然,这里也可以不创建变量,但需注意, 分号一定不能丢 !

顺带一提,好像只要顺序正确,都能编译成功:
在这里插入图片描述
不过这样的代码过于恶心,这里只是尝试一下,平时可不敢这样写😂。

2.2变量的创建与初始化

创建:

struct Stu
{char name[20];int age;int tele;
}s1;
struct Stu S2;
int main()
{struct Stu S3;return 0;
}

S1、S2为全局变量,S3为局部变量


初始化大致分两种:

  • 按原顺序进行初始化
struct Stu s1 = { "张三", 18, 11223344 };
  • 按指定顺序进行初始化
struct Stu s2 = { .age = 81, .tele = 44332211, .name = "李四" };

2.3访问

直接访问
使用.

struct Stu s1 = { "张三", 18, 11223344 };
printf("Name: %s\nAge: %d\nTele: %d\n", s1.name, s1.age, s1.tele);

运行结果如下:
在这里插入图片描述

通过指针访问
常见于数据结构部分,因为这部分的结构体变量大多是在堆上分配的。

struct Stu *p = malloc(sizeof(struct Stu));
if(!p){perror("malloc");return 1;}
strcpy(p->name, "李四");
p->age = 81;
p->tele = 44332211;printf("Name: %s\n", p->name);
printf("Age: %d\n", p->age);
printf("Tele: %s\n", p->tele);free(p);
p = NULL;

运行结果如下:
在这里插入图片描述

一个小细节:

p->name = "李四";
//strcpy(p->name, "李四");

为什么不能写成这样?
在C语言中,字符串常量(如 “李四”)是不可修改的常量数组。
当试图将一个字符串常量赋值给一个字符数组时,编译器会报错:
在这里插入图片描述
因此,需要先创建一个字符数组,然后将字符串strcpy复制到这个数组中。

2.4匿名结构体类型

特点是没有名字,且只能用一次:

struct
{char name[20];int age;int tele;
}s,*ps;

使用时,只能在结构体后创建变量,如s*ps
且,即便两个匿名结构体的成员列表相同,它们依然是两个不同的类型。

3.结构体内存对齐

先来看看下面这段代码:

struct S1
{char c1;int n;char c2;
};
struct S2
{char c1;char c2;int n;
};
int main()
{printf("%zd\n",sizeof(struct S1));printf("%zd\n",sizeof(struct S2));return 0;
}

运行结果如下:

12
8

如果单纯的将成员列表中各个成员的大小相加,那么S1、S2都应该是6字节。
但是很遗憾,不仅不是6字节,S1、S2的大小甚至都不一样,这是为什么呢?

结构体的大小不是结构体元素单纯相加就行的,因为主流的计算机使用的都是32bit字长的CPU,对这类型的CPU取4个字节的数要比取一个字节要高效,也更方便。所以在结构体中每个成员的首地址都是4的整数倍的话,取数据元素时就会相对更高效,这就是内存对齐的由来。

3.1对齐规则

  1. 第一个成员对齐到偏移量为0的位置。
  2. 之后的成员对齐,对齐到对齐数的整数倍处。
  3. 总大小需是最大对齐数的整数倍。

对齐数

  • 常见类型的对齐数,按默认对齐数和自身长度,较小的那个进行
  • 数组的对齐数,按默认对齐数和自身成员长度,较小的那个进行
  • 结构体的对齐数,按默认对齐数和自身成员最大长度,较小的那个进行

默认对齐数
每个特定平台上的编译器都有自己的默认对齐数,如VS上的是8。
也可以通过预编译指令修改默认对齐数:

#pragma pack(n)

注:这里的n最好取2的倍数

3.2示例

下面我将给出多个结构体,并解释它们的大小是如何得到的。


struct S1
{char c1;char c2;int n;
}

先将c1存入偏移量为0的位置,占一字节:
在这里插入图片描述
再存c2,计算得对齐数为1,因此存入偏移量为1的位置,占一字节:
在这里插入图片描述
再存n,计算得对齐数为4,因此存入偏移量为4的位置,占四字节:
在这里插入图片描述
最后,最大对齐数为4,因此大小为8


struct S2
{char c1;int n;char c2;
};

先将c1存入偏移量为0的位置,占一字节:
在这里插入图片描述
再存n,计算得对齐数为4,因此存入偏移量为4的位置,占四字节:
在这里插入图片描述
再存c2,计算得对齐数为1,因此存入偏移量为8的位置,占一字节:
在这里插入图片描述
最后,最大对齐数为4,因此大小为12


struct S3
{short n;char c;int i;
};

先将n存入偏移量为0的位置,占两字节:
在这里插入图片描述

再存c,计算得对齐数为1,因此存入偏移量为2的位置,占一字节:
在这里插入图片描述

再存i,计算得对齐数为4,因此存入偏移量为4的位置,占四字节:

在这里插入图片描述

最后,最大对齐数为4,因此大小为8


struct S4
{char c;struct S3 s3;double d;
};

先将c存入偏移量为0的位置,占一字节:
在这里插入图片描述
再存S3,计算得对齐数为4,因此存入偏移量为4的位置,占八字节:
在这里插入图片描述
再存d,计算得对齐数为8,因此存入偏移量为16的位置,占八字节:
在这里插入图片描述
最后,最大对齐数为8,因此大小为24


希望本篇文章对你有所帮助!并激发你进一步探索C语言的兴趣!

本人仅是个C语言初学者,如果你有任何疑问或建议,欢迎随时留言讨论!让我们一起学习,共同进步!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python 从入门到实战20(函数的返回值等)

我们的目标是:通过这一套资料学习下来,通过熟练掌握python基础,然后结合经典实例、实践相结合,使我们完全掌握python,并做到独立完成项目开发的能力。 上篇文章我们讨论了函数的参数。今天我们继续学习一下函数的返回…

SysML图例-农业无人机

DDD领域驱动设计批评文集>> 《软件方法》强化自测题集>> 《软件方法》各章合集>>

数据结构—双向链表

结构 带头链表里的头结点&#xff0c;实际为“哨兵位”&#xff0c;哨兵位结点不存储任何有效元素&#xff0c;只是站在这里“放哨 的” 实现双向链表 List.h #pragma once#include<stdio.h> #include<stdlib.h> #include<assert.h> #include<stdbool…

Mac 上,终端如何开启 proxy

前提 确保你的浏览器可以访问 google&#xff0c;就是得先有这个能力 步骤 查看网络的 http/https 还有 socks5 的 port配置 .zshrc 查看 port 点击 wifi 设置 以我的为例&#xff0c;我的 http/https 都是 7890&#xff0c; socks5 是 7891 查看代理的port 以我的软件…

文件误删除后的数据救援实战指南

在数字化时代&#xff0c;文件误删除成为了许多用户心头挥之不去的阴影。无论是手误点击了“删除”键&#xff0c;还是系统崩溃导致的数据丢失&#xff0c;文件一旦从我们的视线中消失&#xff0c;往往伴随着重要信息的流失和工作的中断。本文将深入探讨文件误删除的现象&#…

打造高效实时数仓,从Hive到OceanBase的经验分享

本文作者&#xff1a;Coolmoon1202&#xff0c;大数据高级工程师&#xff0c;专注于高性能软件架构设计 我们的业务主要围绕出行领域&#xff0c;鉴于初期采用的数据仓库方案面临高延迟、低效率等挑战&#xff0c;我们踏上了探索新数仓解决方案的征途。本文分享了我们在方案筛选…

Java开发安全及防护

目录 一、开发安全 二、XSS介绍及防范措施 2.1何为XSS 2.2XSS分类 2.3常用方法 三、SQL注入介绍及防范措施 3.1何为SQL注入 3.2常用方法 四、重放介绍及防范措施 4.1何为重放 4.2常用方法 一、开发安全 在学习安全之前&#xff0c;我们首先学习漏洞&#xff0c;知道…

视频格式转为mp4(使用ffmpeg)

1、首先安装ffmpeg&#xff0c;下载链接如下 https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-6.1.1-full_build.7z 安装后确保ffmpeg程序加到PATH路径里&#xff0c;cmd执行ffmpeg -version出现下图内容表示安装成功。 2、粘贴下面的脚本到文本文件中&#xff0c;文件后缀…

【Python笔记】PyCharm大模型项目环境配置

一、PyCharm创建新项目 二、更新pip版本 ...>python.exe -m pip install --upgrade pip 三、生成所需requirements配置文件 ...>pip freeze > requirements.txt 四、安装所需组件requirements.txt ...>pip install -r requirements.txt

基于代理的分布式身份管理方案

目的是使用分布式的联合计算分发去替换掉区块链中原有的类第三方可信中心的证书机制&#xff0c;更加去中心化。 GS-TBK Group Signatures with Time-bound Keys. CS-TBK 算法 Complete subtree With Time-bound Keys&#xff0c;该算法是用来辅助检测用户的签名是否有效&…

微服务_入门2

文章目录 一、Feign 一、Feign 来看我们以前利用RestTemplate发起远程调用的代码&#xff1a; 存在下面的问题&#xff1a; 代码可读性差&#xff0c;编程体验不统一参数复杂URL难以维护&#xff08;有时候访问一个页面所携带的参数是非常多的&#xff09; Feign是一个声明…

CSS——网格布局(display: grid)之上篇

CSS——网格布局&#xff08;display: grid&#xff09; 前面介绍了弹性布局&#xff0c;今天我们介绍一下网格布局。 什么是网格布局 CSS网格布局&#xff08;CSS Grid Layout&#xff09;是一种用于创建复杂网页布局的系统&#xff0c;它允许开发者以二维系统&#xff08;…

双三次插值及MATLAB实现

一、双三次插值的概念 双三次插值&#xff08;Bicubic interpolation&#xff09;&#xff0c;又叫双立方插值。在数值分析这个数学分支中&#xff0c;双三次插值是二维空间中最常用的插值方法。在这种方法中&#xff0c;函数f在点 (x0 ,y0) 的值不仅考虑其直接邻接点对其的影响…

Leetcode—1137. 第 N 个泰波那契数【简单】

2024每日刷题&#xff08;160&#xff09; Leetcode—1137. 第 N 个泰波那契数 记忆化搜索实现代码 class Solution { public:int tribonacci(int n) {int zero 0;int one 1;int two 1;if(n 0) {return zero;}if(n 1) {return one;}if(n 2) {return two;}int ans 0;fo…

MATLAB、FPGA、STM32中调用FFT计算频率、幅值及相位差

系列文章目录 文章目录 系列文章目录前言MATLABSTM32调用DSPSTM32中实现FFT关于初相位 FPGA 前言 最近在学习如何在STM32中调用FFT MATLAB 首先对FFT进行一下说明&#xff0c;我们输入N个点的数据到FFT中&#xff0c;FFT会返回N个点的数据&#xff0c;这些数据都是复数&#…

【ACM出版】第三届人工智能与智能信息处理国际学术会议(AIIIP 2024,10月25-27)

第三届人工智能与智能信息处理国际学术会议&#xff08;AIIIP 2024&#xff09; 2024 3rd International Conference on Artificial Intelligence and Intelligent Information Processing 中国-天津 | 2024年10月25-27日 | 会议官网&#xff1a;www.aiiip.net 官方信息 会议…

智能客服自动化新体验:Function Calling让问题处理更高效

Function Calling作为一项创新功能&#xff0c;正深刻改变着大模型与实际产业之间的融合方式。它不仅**为大模型增添了与外部工具和API无缝连接的能力&#xff0c;助力大模型向实际产业落地迈进&#xff1b;还极大地简化了开发者与模型间的交互流程&#xff0c;使得开发者从模型…

Leetcode—1184. 公交站间的距离【简单】

2024每日刷题&#xff08;161&#xff09; Leetcode—1184. 公交站间的距离 实现代码 class Solution { public:int distanceBetweenBusStops(vector<int>& distance, int start, int destination) {int clockwise 0;int counterclockwise 0;if(start > desti…

RabbitMQ(高阶使用)死信队列

文章内容是学习过程中的知识总结&#xff0c;如有纰漏&#xff0c;欢迎指正 文章目录 一、什么是死信队列&#xff1f; 二、死信队列使用场景 三、死信队列如何使用 四、打车超时处理 1.打车超时实现 以下是本篇文章正文内容 一、什么是死信队列&#xff1f; 先从概念解释上搞…

linux入门到实操-4 linux系统网络配置、连接测试、网络连接模式、修改静态IP、配置主机名

教程来源&#xff1a;B站视频BV1WY4y1H7d3 3天搞定Linux&#xff0c;1天搞定Shell&#xff0c;清华学神带你通关_哔哩哔哩_bilibili 整理汇总的课程内容笔记和课程资料&#xff08;包含课程同版本linux系统文件等内容&#xff09;&#xff0c;供大家学习交流下载&#xff1a;…