自定义类型:结构体,声明,变量初始化,结构体内存对齐。

简介: ✅<1>主页:C语言的前男友📃<2>知识讲解:结构体,声明,变量初始化,结构体内存对齐🔥<3>创作者:C语言的前男友☂️<4>开发环境:Visual Studio 2022💬<5>前言:关于结构体我们已经不陌生了,今天我们就来系统的聊一聊结构体的声明,初始化,结构体占的内存大小。

一.结构体

//结构体声明
struct Stu
{
  char name[20];//名字
  int age;//年龄
  char sex[5];//性别
  char id[20];//学号
};


67ead548cd7b46cc8ea1ad6703af9199.png


二.特殊的结构体声明

 在声明结构的时候,可以不完全的声明——匿名结构体类型。

//匿名结构体类型
struct
{
    int a;
    char b;
    float c;
}x;
struct
{
    int a;
    char b;
    float c;
}a[20], *p;

上面的两个结构在声明的时候省略掉了结构体标签。

那么问题来了?在上面代码的基础上,下面的代码合法吗?

p = &x;

注意:编译器会把上面的两个声明当成完全不同的两个类型。所以是非法的。


三.结构体自引用

 在结构中包含一个类型为该结构本身的成员是否可以呢?

struct Node
{
    int data;
    struct Node next;
};
可行否?如果可以,那sizeof(struct Node)是多少?



这里显然是不行的。但是是不是就意味着就不行了呢?还是有办法实现自引用的。

正确的结构体自引用方式
struct Node
{
    int data;
    struct Node* next;
};


四.注意:

如果加上 typedef 是不是就可以这样实现结构体自引用呢? 
typedef struct
{
  int data;
  Node* next;
}Node;
这样写代码是不行的
解决方案:
typedef struct Node
{
  int data;
  struct Node* next;
}Node;


五.结构体的定义和初始化

struct Point
{
    int x;
    int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//初始化:定义变量的同时赋初值。
struct Point p3 = {x, y};
struct Stu     //类型声明
{
    char name[15];//名字
    int age;    //年龄
};
struct Stu s = {"zhangsan", 20};//初始化
struct Node
{
    int data;
    struct Point p;
    struct Node* next;
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化
struct Stu
{
  char name[20];
  int age;
  char ID[20];
};
int main()
{
  按照结构体顺序初始化变量
  struct Stu stu2 = { "ikun",20,"JNTM123" };
  自定义顺序初始化变量
  struct Stu stu1 = { .ID = "CZU123",.age = 19,.name = "张三" };
  return 0;
}


六.结构体内存对齐

我们已经掌握了结构体的基本使用了,那么一个结构体到底时多大呢?到底怎么计算呢?

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

大家可以猜一下结果


22225b594d30476c918b03631b4ace70.png


结果是不是出乎大家的意料了,虽然结构的成员都是一样的,但是结构的大小却不一样。


到底是为什么造成这样的结果呢?其实结构体的大小可不是简单的结构体成员大小加在一起的。


而是有一种内存对齐的规则。


结构体的对齐规则:

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

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。(VS中默认的值为8)

3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

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

体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。


下面我们就对着这个规则来做几个例子:

(1)例一:

struct S1
{
  char c1;
  int a;
  char c2;
};
求结构体s1的大小



运行效果:



(2)例二:

1.题目:

struct S2
{
    char c1;
    char c2;
    int i;
};
求结构体 S2 的大小


2.图解:


3.运行效果:



(3)例三:

1.题目:

struct S1
{
  char c1;
  int a;
  char c2;
};
struct S2
{
    char c1;
    struct S1 S;
    char c2;
    int i;
};
//求结构体S2的大小

2.图解:



运行结果:



七、为什么存在内存对齐

(1) 平台原因(移植原因):


不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特

定类型的数据,否则抛出硬件异常。


(2) 性能原因:


数据结构(尤其是栈)应该尽可能地在自然边界上对齐。

原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访

问。


总体来说:


结构体的内存对齐是拿空间来换取时间的做法。

那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:

让占用空间小的成员尽量集中在一起。

例如:

struct S1
{
    char c1;
    int i;
    char c2;
};
struct S2
{
    char c1;
    char c2;
    int i;
};

s2就比s1更节省空间。


四.修改默认对齐数

#pragma pack();

例一:

#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
struct S1
{
  char c1;
  int i;
  char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{
  char c1;
  int i;
  char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
  //输出的结果是什么?
  printf("%d\n", sizeof(struct S1));
  printf("%d\n", sizeof(struct S2));
    return 0;
}

运行结果:



例二:

#include <stdio.h>
#pragma pack(1)//设置默认对齐数为8
struct S1
{
  char c1;
  int i;
  char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1
struct S2
{
  char c1;
  int i;
  char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
  //输出的结果是什么?
  printf("%d\n", sizeof(struct S1));
  printf("%d\n", sizeof(struct S2));
    return 0;
}


运行结果:



最后:

不操千曲而后晓声,观千剑而后识器。


2.jpg

 

相关文章
|
8月前
|
存储 人工智能 安全
AI驱动的幼儿跌倒检测——视频安全系统的技术解析
幼儿跌倒检测系统基于AI视频技术,融合人体姿态识别与实时报警功能,为幼儿园安全管理提供智能化解决方案。系统通过YOLOv9、OpenPose等算法实现高精度跌倒检测(准确率达98%),结合LSTM时间序列分析减少误报,支持目标分类区分幼儿与成人,并具备事件存储、实时通知及开源部署优势。其高效、灵活、隐私合规的特点显著提升安全管理效率,助力优化园所运营。
377 0
AI驱动的幼儿跌倒检测——视频安全系统的技术解析
TO B产品经理:每个阶段的学习与提升之路
对于TO B产品经理来说,每个阶段都是一次学习和提升的机会。从建立基础到深化专业知识,再到提升战略眼光和持续创新与学习,每一步都需要付出努力和汗水。但正是这样的不断学习和提升,让TO B产品经理能够在竞争激烈的市场中脱颖而出,成为企业和商业世界之间的优秀桥梁。
|
9月前
|
前端开发 UED
在React Router中,如何处理路由的404错误页面?
在React Router中,如何处理路由的404错误页面?
343 57
|
11月前
|
Ubuntu NoSQL 开发工具
《docker基础篇:4.Docker镜像》包括是什么、分层的镜像、UnionFS(联合文件系统)、docker镜像的加载原理、为什么docker镜像要采用这种分层结构呢、docker镜像commit
《docker基础篇:4.Docker镜像》包括是什么、分层的镜像、UnionFS(联合文件系统)、docker镜像的加载原理、为什么docker镜像要采用这种分层结构呢、docker镜像commit
523 70
|
9月前
|
机器学习/深度学习 人工智能 运维
机器学习+自动化运维:让服务器自己修Bug,运维变轻松!
机器学习+自动化运维:让服务器自己修Bug,运维变轻松!
403 14
|
9月前
|
监控 算法 安全
公司电脑网络监控场景下 Python 广度优先搜索算法的深度剖析
在数字化办公时代,公司电脑网络监控至关重要。广度优先搜索(BFS)算法在构建网络拓扑、检测安全威胁和优化资源分配方面发挥重要作用。通过Python代码示例展示其应用流程,助力企业提升网络安全与效率。未来,更多创新算法将融入该领域,保障企业数字化发展。
235 10
|
10月前
|
人工智能 自然语言处理 算法
DeepSeek vs ChatGPT:AI对决中的赢家是……人类吗?
DeepSeek VS ChatGPT:DeepSeek以开源黑马姿态崛起,凭借低成本、高性能的「DeepSeek-V3」和专为深度推理设计的「DeepSeek-R1」,成为中小开发者的首选。而ChatGPT则较贵。 然而,AI依赖也带来隐忧,长期使用可能导致记忆衰退和“脑雾”现象。为此,推荐Neuriva解决方案,专注力提升30%,记忆留存率提升2.1倍,助力人类在AI时代保持脑力巅峰。 DeepSeek赢在技术普惠,ChatGPT胜于生态构建,人类的关键在于平衡AI与脑力健康,实现“双核驱动”突破极限!
1090 7
|
11月前
|
程序员 开发者
30 + 程序员的职场渡劫,差点被裁后我翻身了
阿飞,30+的一线城市程序员,在互联网公司工作五年后遭遇裁员危机和高强度加班。使用飞算JavaAI后,工作效率大幅提升,不仅告别了无效加班,还获得了领导的认可与晋升机会。业余时间增多,生活品质提高。现推荐参加“飞算JavaAI炫技大赛”,低门槛高奖励,参赛即有机会赢取丰厚奖品,释放编程潜力。
|
10月前
|
人工智能 数据可视化 程序员
100 名 AI 程序员体验官都在用通义灵码干什么?
通义灵码联合阿里云开发者社区,全网寻找 100 位 AI 程序员体验官,感受 AI 程序员和满血版 Deepseek 加持下的智能编码新功能,体验需求开发、跨语言编程、单元测试自动生成、图生代码等能力,领取 Cherry 机械键盘、智能手环等奖品。我们看看体验官们用通义灵码都干了什么?
|
机器学习/深度学习 TensorFlow 算法框架/工具
使用卷积神经网络(CNN)进行图像分类与识别
使用卷积神经网络(CNN)进行图像分类与识别
2210 0