详解结构体

简介: 详解结构体

结构体

为什么要创建结构体类型?在我们处理复杂对象的时候,比如描述一个人的时候,它有名字,性别,身高,体重等一些方面的特征。用结构体打包描述的时候就比较方便。

结构体类型的声明

结构体类型的关键字struct

声明的基本模板为:

struct 标签
{

成员;
}变量;

结构体的成员可以是不同的类型。

结构体类型的特殊声明:

匿名结构体类型,它只能使用一次。

struct
{
  int a;
  char b;
}x;
struct
{
  int a;
  char b;
}*p;

p=&x这样写是错误的,在编译器看来,它们俩是不同的类型。

看下面这两种:

struct
{
  int a;
  int b;
}x;
这里的x是一个结构体类型的全局变量
typedef struct
{
  int a;
  int b;
}x;
这里的x是结构体类型。
typedef struct stu
{
  int a;
  int b;
}*put,stu;
这里的put等价于struct stu*类型
stu等价于struct stu类型

结构的自引用

例如:

typedef struct node
{
  int x;
  struct node* p;
}node;
这个自引用就是正确的。
typedef struct node
{
  int x;
  node* p;
}node;
这种就是错误的,这个问题的出现就和先有鸡还是先有蛋的问题一样。
不能知道是先重命名了还是先创建的。

结构体变量的定义和初始化

  • 结构体变量的定义
struct student
{
  char name[20];
  int age;
}a,b;
//这种是一边声明,一边定义变量的,这里的变量a,b为全局变量
struct student c;
//这种定义的变量是全局变量
int main()
{
  struct student d;
  //这里的d为局部变量
  return 0;
}
  • 简单的初始一下:(应该没有难道吧)
struct student
{
  char name[20];
  int age;
}a={"zhangshan",20}, b={"wuanwu",18};
struct student c={"hh",0};
int main()
{
  struct student d={"sb",88};
  return 0;
}

🟥结构体内存对齐

如何计算结构体的大小,就需要知道它在内存中是如何储存的。

而结构体在内存中存在结构体对齐的现象。

1.第一个成员变量放在偏移量为0的位置

2.后面的成员放在偏移量为对齐数的整数倍的位置。

3.对齐数:编译器默认的一个对齐数与成员大小的较小值

vs的默认对齐数位8

4.结构体的总大小为每个成员默认最大对齐数的整数倍。

5.如果含有结构体嵌套的情况,镶嵌的那个结构体的对齐数是里面成员的最大对齐数。

  • 下面仔细讲解一下:
  struct S1
  {
    char c1;
    int i;
    char c2;
  };
  printf("%d\n", sizeof(struct S1));

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

  struct S3
  {
    double d;
    char c;
    int i;
  };
  printf("%d\n", sizeof(struct S3));

  struct S4
  {
    char c1;
    struct S3 s3;
    double d;
  };
  printf("%d\n", sizeof(struct S4));

按上面的分析:可知结构体的大小分别为:12,8,16,32

运行看一下情况:

修改默认对齐数

我们用pragma修改默认对齐数

例子:

#pragma pack(4)
//这里面的数字表示的是默认对齐数
struct p
{
  int a;
  int b;
  char c;
};
#pragma pack()

结构体传参

在结构体传参的时候,最好选择传址调用,有两个好处

1.可以减少对空间的浪费

2.可以对里面的数据进行修改

简单的例子:

#include <stdio.h>
struct student
{
  char name[20];
  int age;
};
void f(struct student* p)
{

}
int main()
{
  struct student p;
  f(&p);
  return 0;
}

结构体实现位段

位段的实现和结构体类似,只不过位段的成员的类型只能是

unsigned int 或者int类型,char类型的也可以。

每个成员名后面要加上:和数字

举个简单的例子:

struct stu
{
  int a : 4;
  int b : 2;
};

后面的数字表示bite位。位段不存在对齐。

位段不具有跨平台性:

1.位段中没有规定在内存使用的过程中,是从左使用还是从右使用。

2.不能满足下一个成员使用的空间是舍弃还是保留的问题没有规定。

3.int位段中无符号还是有符号的问题没有规定

结构体实现位段的内存分配

struct S
{
  char a : 3;
  char b : 4;
  char c : 5;
  char d : 4;
};
struct S s = { 0 };
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

枚举

枚举类型的关键字为enum,枚举就是把所有的可能列举出来。

里面的叫做枚举常量。它们也是有值的,如果没有给他们初始化。默认第一个是0,后面的依次增加。

例子:

enum colour
{
  //注意后面是逗号,
  red,//值是0
  yellow,//值是1
  green//值是2
};


enum colour
{
  red=2,//这种不是赋值,而是给这个常量一个初始值。
  yellow=5,
  green//它的值为6
};

联合(共用体)

联合类型的定义

关键字union

里面的成员都是占用同一块空间。

例子:

union people
{
  char a;
  int b;
};

联合大小的计算

联合体可能是最大类型所占空间的大小。

当结构体的大小不是最大对齐数的整数倍时,需要对齐。

例子:

union Un1
{
  char c[5];
  //开辟了5个字节的空间
  int i;
  //i占4个大小的空间,开辟的空间够用
  //共5个字节的空间,但是不是4的整数倍,存在内存对齐,
  //最终为8个字节的大小
};
union Un2
{
  short c[7];
  int i;
  //开辟的14个字节的空间也不是4的整数倍,需要对齐。
  //最终的大小为16个字节
};
int main()
{
  printf("%d\n", sizeof(union Un1));
  printf("%d\n", sizeof(union Un2));
  return 0;
}

看结果:

相关文章
|
2月前
|
JSON 数据安全/隐私保护 数据格式
拼多多批量下单软件,拼多多无限账号下单软件,python框架仅供学习参考
完整的拼多多自动化下单框架,包含登录、搜索商品、获取商品列表、下单等功能。
|
3月前
|
Ubuntu Linux Shell
Linux环境下VSCode快速安装终极指南:debian/ubuntu/linux平台通用
以上就是在Linux环境下安装VSCode的终极指南,抛开繁复的专业词汇,以平易近人的文字、形象生动的比喻让你轻松学会这一过程。别忘了,你的小伙伴VSCode已经在应用菜单里等你了!
847 23
Linux:nohup、&、 2>&1、/dev/null
Linux:nohup、&、 2>&1、/dev/null
|
缓存 人工智能 算法
Nvidia_Mellanox_CX5和6DX系列网卡_RDMA_RoCE_无损和有损_DCQCN拥塞控制等技术简介-一文入门RDMA和RoCE有损无损
Nvidia_Mellanox_CX5和6DX系列网卡_RDMA_RoCE_无损和有损_DCQCN拥塞控制等技术简介-一文入门RDMA和RoCE有损无损
2934 0
|
Web App开发 数据可视化 Docker
|
12月前
|
SQL 数据库
SQL error : “No query“问题参考
本文介绍了解决SQL中"No query"错误的步骤,包括错误提示、正确的SQL语句写法,以及更多相关参考信息。错误的原因是在构建更新语句时字段赋值之间缺少逗号,导致SQL解析失败。文章还提供了正确格式的SQL语句和相关错误处理的参考链接。
198 3
SQL error : “No query“问题参考
|
10月前
|
Kubernetes 监控 Java
如何设置 Kubernetes的垃圾回收策略为定期
如何设置 Kubernetes的垃圾回收策略为定期
|
11月前
|
机器学习/深度学习 自然语言处理
【绝技揭秘】模型微调与RAG神技合璧——看深度学习高手如何玩转数据,缔造预测传奇!
【10月更文挑战第5天】随着深度学习的发展,预训练模型因泛化能力和高效训练而备受关注。直接应用预训练模型常难达最佳效果,需进行微调以适应特定任务。本文介绍模型微调方法,并通过Hugging Face的Transformers库演示BERT微调过程。同时,文章探讨了检索增强生成(RAG)技术,该技术结合检索和生成模型,在开放域问答中表现出色。通过实际案例展示了RAG的工作原理及优势,提供了微调和RAG应用的深入理解。
310 0
|
11月前
|
网络协议 算法
RPC为何比较高效?
RPC为何比较高效?
187 0
|
小程序 JavaScript Java
基于Java微信小程序火锅店点餐系统设计和实现(源码+LW+调试文档+讲解等)
基于Java微信小程序火锅店点餐系统设计和实现(源码+LW+调试文档+讲解等)