【C语言】struct结构体
文章目录
- 一. 结构体简述
- 二. 结构体的声明和定义
- 1、简单地声明一个结构体和定义结构体变量
- 2、声明结构体的同时也定义结构体变量
- 3、匿名结构体
- 4、配合typedef,声明结构体的同时为结构体取别名
- 5、在声明匿名结构体时,使用typedef给这个匿名结构体取别名
- 三. 结构体变量的初始化
- 四. 结构体成员的访问方法
- 五. 结构体大小的计算
- 1. 计算方法
- 2. 普通结构体
- 3. 包含数组成员的结构体
- 4. 成员包含结构体的结构体
- 5. 成员包含联合体的结构体
- 6. 空结构体的大小
- 六. 柔性数组
- 1. 介绍
- 2. 使用方法
- 3. 柔性数组的特点
- 七. C++ 中 struct 与 class 的区别
- 八. C 和 C++ 结构体的区别
一. 结构体简述
具有相同或不同类型元素的集合叫做结构体。定义一个结构体,本质是在制作一个类型:
// 声明一个学生信息结构体
struct Student
{char name[20];int age;
};int main()
{// 定义出两个学生变量struct Student s1 = { "张三", 18};struct Student s2 = { "李四", 20};return 0;
}
二. 结构体的声明和定义
1、简单地声明一个结构体和定义结构体变量
在C中,结构体内只能存放各种类型的变量,不能存函数:
像上面这样就是声明了一个结构体struct Student
,此时的 struct Student
相当于一个类型名。
然后我们可以用这个自己声明的结构体类型去定义变量:
补充:C 和 C++ 中定义结构体变量的区别
- 在 C 中使用结构体去定义变量时,需要在结构体名称前加上 struct 关键字。
- 在 C++ 中使用结构体去定义变量时,可以不加 struct 关键字
2、声明结构体的同时也定义结构体变量
也许初期看不习惯容易困惑,其实这就相当于两步合并一步:先定义结构体 struct Student,再定义变量 s1 和 s2:
3、匿名结构体
使用方式:声明结构体的时候缺失结构体名,同时定义出一个或n个结构体变量:
这种形式只能使用在声明结构体的同时也定义出结构体变量,由于没有结构体名,因此后续不可以再定义新的结构体变量。
4、配合typedef,声明结构体的同时为结构体取别名
前面说过,使用结构体去定义结构体变量时,C 需要加 struct,C++ 不需要。那么使用结构体的别名去定义变量呢?
答:使用结构体别名去定义结构体变量时,C 和 C++ 都不需要加 struct,加了反而都会报错,因为取别名时把struct连同结构体名称一起包含进去了。
5、在声明匿名结构体时,使用typedef给这个匿名结构体取别名
这种形式声明了一个缺失结构体名的结构体,但同时使用 typedef 为结构体设置了别名,所以之后我们可以使用这个别名,去定义结构体变量。
三. 结构体变量的初始化
先弄清楚变量初始化和赋值的区别:
struct Student
{char name[20];int age;
};int main()
{// 变量刚开始创建时给值,这个叫初始化struct Student s1 = {"nick", 18};// 变量创建后,再对它的值进行操作这个叫赋值strcpy(s1.name, "tony");s1.age = 24;return 0;
}
结构体只能被整体初始化,不能被整体赋值,想要赋值的话只能把成员逐个地取出来再赋值。
补充:数组也是一样的道理:只能整体初始化,不能整体赋值。如果是字符数组想要整体赋值的话,可以使用 strcpy
函数:
本人推测结构体和数组不能被整体赋值的原因是:它们内部空间在逻辑上是独立一块块的,所以我们只能对这些独立的空间逐个赋值,而不能整体赋值。
四. 结构体成员的访问方法
我们可以通过变量或变量的地址去访问结构体的成员。
struct Student
{char name[20];int age;
};int main()
{// 1、通过变量访问结构体成员struct Student s;strcpy(s.name, "张三");s.age = 18;// 2、通过指针访问结构体成员struct Student* p = &s;printf("%s\n", p->name);printf("%d\n", p->age);return 0;
}--------结果如下--------
张三
18
为什么结构体会有两种访问方式?
在函数传参(传值、传址)时,会生成临时变量,如果要传的结构体变量太大的话,传值拷贝出来的临时对象也会很大,如果用传地址的方式来传结构体变量地址的话,可以很好的节省空间。
当然如果可以直接拿到结构体变量的话,使用变量来访问结构体成员会更直观点。
五. 结构体大小的计算
1. 计算方法
结构体的大小不是结构体元素单纯相加就行的,因为我们现在主流的计算机使用的都是64位字长的CPU,对这类型的CPU取8个字节的数要比取一个字节要高效,也更方便。所以在结构体中每个成员的首地址都是8的整数倍的话,取数据元素时就会相对更高效,这就是内存对齐的由来。每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n)
来改变这一系数,其中的 n 就是你要指定的“对齐系数”。
但实际每个成员的类型可能是不同的,每个类型对应不同大小,为了更高效地读取结构体变量的成员,结构体的大小要遵循一套对齐规则:
- 第一个成员在与结构体变量偏移量为0的地址处。(即结构体的首地址处,即对齐到0处)
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
- 结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
- 如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
对齐数 = 该结构体成员变量自身的大小与编译器默认的一个对齐数的较小值。
PS:VS中的默认对齐数为8,不是所有编译器都有默认对齐数,当编译器没有默认对齐数的时候,成员变量的大小就是该成员的对齐数。
2. 普通结构体
第一步:找出每个成员变量的大小将其与编译器的默认对齐数相比较,取其较小值为该成员变量的对齐数
PS:这里使用的是VS编译器,故默认对齐数为8。
第二步:根据每个成员对应的对齐数画出它们在内存中的相对位置
第三步:通过最大对齐数决定最终该结构体的大小
通过图我们可以知道,绿色部分(double d成员占用)+红色部分(char c成员占用)+紫色部分(int i成员占用)+红色与紫色之间的白色部分(浪费掉了)总共占用了16个字节的内存空间。
我们需要将它们总共占用的内存空间(16)与结构体成员的最大对齐数(8)相比较,结构体的总大小为最大对齐数的整数倍,此时16正好是8的整数倍,所以该结构体在VS编译器下的大小就16个字节。即创建一个该类型的结构体变量,内存需为其开辟16个字节的内存空间。
PS:大多数情况下,成员变量已经占用的总字节个数并不一定正好为其成员变量中的最大对齐数的整数倍,这时我们需要将其扩大为最大对齐数的整数倍。
3. 包含数组成员的结构体
数组应拆开来看,不能看做一个整体
struct S
{char a; //对齐数为1。占1个字节char c[5]; //对齐数为1。可看成5个char占5个字节int b; //对齐数为4。占4个字节,因为前面所有成员占6个字节,不是4//个字节的整数倍,所以在第二个成员和第三个成员//之间要补2个字节
} //所以该结构体的大小为1+5+2(补)+4=12个字节
4. 成员包含结构体的结构体
1)如果结构体成员只是说明而没有定义变量,则这个结构体成员不占内存空间。
struct S
{char a; //对齐数为1。占1个字节struct s{int c;char d;}; //此处结构体只声明,没有定义结构体变量,所以该声明//的结构体在地址空间中并不占位置int f; //对齐数为4。占4个字节double b; //对齐数为8,
}; //该结构体的大小为1+3(补)+4+8=16个字节
2)如果内部定义并申明了其他结构体变量,这时需要把这个结构体看成一个整体,大小要独立计算,至于对齐数取其内部最大成员的对齐数。
struct t
{char a; //对齐数1struct s //对齐数4{int c; //对齐数4char d;//对齐数1}g;//此处定义并申明了结构体变量,在这里需要把结构体//看成一个整体,独立计算这个结构体的大小为8字节//结构体整体的对齐数是内部最大成员的对齐数//之后把这个结构体看出对齐数为4,大小为8的成员char f; //对齐数1int b; //对齐数4
}; //所以该结构体的大小为1+3(补)+8+1+3(补)+4=20个字节
5. 成员包含联合体的结构体
联合体的大小等同于联合体里面最大成员的大小,所以可以把联合体等效成一个变量,这个变量就是联合体里面最大的那个成员。
和前文所说的结构体一样,如果只声明联合体,没定义联合体变量,则联合体就当成不存在。
struct t
{char a;union s{int c;char d;double h;}g; int f;double b;
};//所以该结构体的大小为1+7(补)+8+4+4(补)+8=32个字节
6. 空结构体的大小
1)在 VS2017 下测试
2)在 Centos7 下测试
六. 柔性数组
1. 介绍
在 c99 中有明确的规定允许结构体中最后一个数组大小是未知的。
- 数组作为结构体的最后一个成员
- 数组元素可以不写或写成0
- 结构体中至少包含一个以上处数组外的其他类型的成员
struct T
{int a;char b;int arr[];//或者int arr[0];};int main()
{struct T t;// sizeof 求结构体大小时所求出的大小没有包括柔性数组的大小printf("%lu\n", sizeof(struct T));return 0;
}--------结果如下--------
8
2. 使用方法
包含柔性数组的结构体,可以把整个结构体看成是变长的。
#include<stdio.h>
#include<stdlib.h>
#include<stdlib.h> struct d
{ int nb; int nn; int arr[];
}; int main()
{//分别给结构体中其他类型的成员和柔性数组申请空间struct d *p=(struct d*)malloc(sizeof(struct d)+5*sizeof(int));p->nb=100;p->nn=50; for(int i=0;i<5;i++){p->arr[i]=i;//赋值printf("%d ",p->arr[i]);} //重新调整所申请的空间,将柔性数组调整为40。struct d *pp=(struct d*)realloc(p,48); if(pp!=NULL){p=pp;for(int i=5;i<10;i++){p->arr[i]=i;//赋值printf("%d ",p->arr[i]); } free(p);p=NULL;} return 0;
} --------结果如下--------
0 1 2 3 4 5 6 7 8 9
3. 柔性数组的特点
- 柔性数组只需在 malloc 创建时要独立于结构体申请空间,此后的 realloc 再分配空间和 free 释放都只需对一个结构体指针操作即可。
- 柔性数组申请的内存更加集中,有利于查找使用和减少内存碎片。
- sizeof 求结构体大小时所求出的大小没有包括柔性数组的大小。
七. C++ 中 struct 与 class 的区别
- class 成员的默认权限为 private,struct 成员的默认权限为 public。
- class 的继承默认是 private 继承,struct 的继承默认是 public 继承。
- class 可以作为一个关键字定义模板参数(与 typename 作用一样),而struct 不可以。
八. C 和 C++ 结构体的区别
- C++ 结构体内部可以有成员变量和成员函数,而 C 中结构体只能有成员变量。
- C 结构体的成员变量不能在声明时给初值,而 C++ 中可以
- C++ 中定义结构变量时,可以不在名称前面加上 struct 关键字,而 C 一定要
- C 结构体内不能有静态成员,而 C++ 可以。
- C 结构没有访问修饰限定符,而 C++ 有。
相关文章:

【C语言】struct结构体
文章目录 一. 结构体简述二. 结构体的声明和定义1、简单地声明一个结构体和定义结构体变量2、声明结构体的同时也定义结构体变量3、匿名结构体4、配合typedef,声明结构体的同时为结构体取别名5、在声明匿名结构体时,使用typedef给这个匿名结构体取别名 三…...

Docker代码环境打包
1. 介绍 Docker是一种开源的容器化平台,它可以在操作系统级别运行应用程序。通过将应用程序及其依赖项封装成一个可移植的容器,Docker使得应用程序可以在任何环境中轻松部署、运行和管理。使用Docker,开发人员可以避免在不同环境中出现的配置…...
现代CMake高级教程 - 第 6 章:输出与变量
双笙子佯谬老师的【公开课】现代CMake高级教程课程笔记 第 6 章:输出与变量 在运行 cmake -B build 时,打印字符串(用于调试) message("Hello world!")❯ cmake --build buildHello world! -- Configuring done -- G…...

windows/linux文件传输
windows系统下文件传输-FTP python安装pyftpdlib模块 pip install pyftpdlib 这里可能会出现报错,自己看着更换源解决 然后运行python,在2121端口监听 python -m pyftpdlib 然后我们可以使用windows命令行进行操作,自己可以去看下相关文…...
Anoconda安装笔记+win10 更改中文用户名为英文
win10 更改中文用户名为英文 ① WinR打开命令窗口,输入regedit 打开注册表, 手动找到 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\ProfileList 在这个目录下面有几个S-1-5-的项,挨个检查每一项, 找到“…...
Java Web应用开发 ——作业七
一.单项选择题(共7题,28.7分) 1 Servlet程序的入口点是( )。 A、 init() B、 main() C、 service() D、 doGet() 正确答案&#…...
echo,date,bc命令详解
文章目录 echo,date,bc命令详解echo(输出文本)date(显示日期的命令)date命令的--date选项date命令 bc(高精度计算器) echo,date,bc命令详解 echo(输出文本) echo命令是一个常用的Shell命令,用于在终端上输出文本。它…...

【Java笔试强训 29】
🎉🎉🎉点进来你就是我的人了博主主页:🙈🙈🙈戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔🤺🤺🤺 目录 一、选择题 二、编程题 🔥求正数数…...
如何在微服务下保证事务的一致性
随着业务的快速发展、业务复杂度越来越高,传统单体应用逐渐暴露出了一些问题,例如开发效率低、可维护性差、架构扩展性差、部署不灵活、健壮性差等等。而微服务架构是将单个服务拆分成一系列小服务,且这些小服务都拥有独立的进程,…...
华为OD机试 - 新学校选址(Python)
题目描述 为了解新学期学生暴涨的问题,小乐村要建立所新学校, 考虑到学生上学安全问题,需要所有学生家到学校的距离最短。 假设学校和所有学生家都走在一条直线之上,请问学校建立在什么位置, 能使得到学校到各个学生家的距离和最短。 输入描述 第一行: 整数 n 取值范围 [1…...

thinkphp6结合layui增删改查综合案列
文章目录 技术栈实现代码实现数据库 本案例适合新手,特别是杠刚入门thinkphp和layui,但又不是特别熟悉这类 主要实现登录退出功能,用户模块的增删改查功能,分页功能是layui表单自带功能 效果图 左侧的菜单栏我没有写对应的页面&am…...
PostgreSQL数据库以任意时间间隔聚合查询group by
文章目录 业务场景以固定时间(年/月/日/时/分/秒)聚合to_char聚合date_trunc聚合 以任意时间聚合date_bin聚合实际应用 业务场景 我们做的是交通信控平台,需要根据实时采集到的交通大数据,计算出一些指标,存储到数据库…...

sql注入(二)盲注,二次注入,宽字节注入
目录 目录 一、布尔盲注 1.判断库名的长度 2.判断数据库名 2.1判断数据库名首字符 2.2 判断数据库名的其余字符 二、时间盲注: 1.判断库名的长度 2.判断库名: 3.判断表名payload: 4.爆出列名 5.爆数据 三、二次注入 1.原理&#…...

Linux 基础操作
Linux学习教程,Linux入门教程(超详细) chown (change owner) : 修改所属用户与组。chmod (change mode) : 修改用户的权限。 要查看文件或目录的属性,可以使用ls命令,加上-l选项。例如ÿ…...

2.4 等比数列
学习步骤: 如果我要学习等比数列,我会按照以下步骤进行学习: 定义和性质:首先了解等比数列的定义和性质,包括公比、首项、通项公式、求和公式等。 例题练习:通过练习一些简单的例题来理解等比数列的概念和…...
2022年新能源汽车专题讲座
2022年新能源汽车专题讲座 单选题(共5题,每题6分) 1、《中华人民共和国数据安全法》自()起施行。 正确答案:C、2021年9月1日 2、典型的智能汽车结构主要分为()个层次。 正确答案…...
Git操作远程仓库
远程仓库 码云 https://gitee.com/ 是国内的一个代码托管平台,由于服务器在国内,所以相比于GitHub,码云速度会更快 码云使用流程 注册账号----登录码云-----点击新建仓库----记得保存地址 GitHub https://github.com/ 是一个面向开源…...

制造策略 ETO、MTO、ATO、MTS
ETO 按交货周期跨度从长到短来讲,首先就是 ETO,Engineer To Order – 面向订单设计、定制生产或特殊生产。 就是客户给的订单,你要生产的话,你之前的原产品改动很大,或者基本上用不上,要完全按照客户的要求…...

Git(六):基本命令(3):储藏、标签、拉取、子模块
目录 17、stash 储藏 17.2 描述 17.3 基本用法 18、tag 标签 18.1 描述 18.2 基本用法 19、fetch 获取 19.1 描述 19.2 基本用法 20、pull 整合 20.1 描述 20.2 基本用法 20.3 pull 与 fetch 的区别 21、push 更新推送 21.1 描述 21.2 基本用法 22、remote 管…...

7.0、Java继承与多态 - 多态的特性
7.0、Java继承与多态 - 多态的特性 面向对象的三大特征:封装性、继承性、多态性; extends继承 或者 implements实现,是多态性的前提; 用学生类创建一个对象 - 小明,他是一个 学生(学生形态)&…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...
大数据驱动企业决策智能化的路径与实践
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:数据驱动的企业竞争力重构 在这个瞬息万变的商业时代,“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...