【C语言】玩转结构体(声明、引用、初始化、内存对齐、传参、位段)

简介: 前言大家好,本文主要深度讲解关于结构体的使用及细节,收录到C—语法专栏,此专栏定期更新C语言语法方面的知识,都是比较详细的,自己复习的同时也希望能帮助到大家,如果有不对或者不足的地方欢迎评论区补充。🏡个人主页:悲伤的猪大肠9的博客-C语言领域博主✨如果文章对你有帮助记得点赞收藏关注哦!!✨🌈重要的不是成功,而是奋斗的过程一、结构体之前我们学过整形(short,int),浮点型(float,double),字符型,还有数组(存储相同类型的数据),但在实际问题中,这些类型显然不够,如果我们想表示一个学生的信息,就会有姓名、年龄、分数。。。这时候就需要一个可以存储不同类型数据

前言

大家好,本文主要深度讲解关于结构体的使用及细节,收录到C—语法专栏,此专栏定期更新C语言语法方面的知识,都是比较详细的,自己复习的同时也希望能帮助到大家,如果有不对或者不足的地方欢迎评论区补充。

🏡个人主页:悲伤的猪大肠9的博客-C语言领域博主

✨如果文章对你有帮助记得点赞收藏关注哦!!✨

🌈重要的不是成功,而是奋斗的过程

一、结构体

之前我们学过整形(short,int),浮点型(float,double),字符型,还有数组(存储相同类型的数据),但在实际问题中,这些类型显然不够,如果我们想表示一个学生的信息,就会有姓名、年龄、分数。。。这时候就需要一个可以存储不同类型数据的数据类型,结构体就此诞生。

1.结构体的声明

//第一种方式
struct student
{
    char name[20];    //结构体中可以放任意类型
    int age;
    float score;
};  //分号不能忘
//第二种方式 在结构体末尾声明结构体实例
struct student
{
    char name[20];  
    int age;
    float score;
}s1;  //s1是全局变量,此时可以根据s1调用结构体
//第三种方式 不声明结构体名称,使其成为匿名结构体
struct
{
    char name[20];  
    int age;
    float score;  
}s1;  //此时只可以使用s1来调用此结构体

2.结构体自引用

  • 结构体是否可以包含自己本身?
//错误示范
struct Node
{
    int data;
    struct Node next;
};
//如果真的可以这样,那sizeof(struct Node)是多少? 岂不是无限大?

那既然这样不可以,那怎么让一个结构体包含自己本身呢。

//正确方法
struct Node
{
    int data;
    struct Node* next;
};

包含结构体指针,这样指针大小是4/8(32/64平台)个字节,就不会出问题.

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

struct student
{
    char name[20];  
    int age;
    float score;
}s1;
struct student s2;  //定义结构体变量s2
struct student s3 = {"ahunb",19,100.0}; //定义s3的同时赋值

嵌套结构体初始化

struct child
{
    char name[20];
    int age;
    struct pet;
}
struct pet
{
    char name[10];
    int age;
}
struct child c1 = {"ahunb",19,{"wangcai",1}};

4.结构体内存对齐

掌握上面知识其实结构体基本使用应该没问题了,但结构体的对齐才是此篇文章的重点,让我们更深入的了解结构体变量。

有这样一个结构体,猜猜他的长度是多少

struct dog
{
  char isWrite;
  int age;
    char isBlack;
};
int main()
{
  printf("%d",sizeof(struct dog));
}

答案是12,why?

重点

结构体在内存对齐的规则:

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

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

对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。

VS中默认的值为8

比如char a[20] 数组,在结构体中的对齐数是1,数组按照数组类型来算,相当于20个char

  1. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
  2. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

内存对齐存在的原因:

  1. 不是所有硬件平台都能访问任意地址数据的,一些平台只能在某些地址取某些特定数据。
  2. 如果没有对齐,会产生两次内存访问,而对齐的只需要进行一次。

结构体内存对齐其实就是那空间换时间

回过头来看上面的题

struct dog
{
  char isWrite; //默认对齐数为4,char对齐数是1,取其小,从1的倍数地址开始占一格
  int age;    //默认对齐数为4,int对齐数为4,取其小,从4倍数地址开始占4格
    char isBlack; //默认对齐数为4,char对齐数是1,取其小,从1的倍数地址开始占1格
};
int main()
{
  printf("%d",sizeof(struct dog)); //结构体大小为最大对齐数的整数倍,最大对齐数是4,12
}

56395180d246477080a86daf74baa6ee.png

默认对齐数可以通过#prama pack( ) 修改

#include <stdio.h>
#pragma pack(1)   //设置默认对齐数为1
struct S1
{
    char c1;    //char对齐数1,默认1,对齐数1
    int i;      //int对齐数4,默认1,对齐数1
    char c2;    //char对齐数1,默认1,对齐数1
};
#pragma pack()    //取消设置的默认对齐数,直接()里什么也不加,还原为默认
int main()
{
    printf("%d\n", sizeof(struct S1));  //数组大小是最大对齐数的倍数,最大对齐数是1,所以总大小是6
    return 0;
}

5.结构体传参

结构体传参最好采用指针传参,不然进行压栈的时候要压入出整个结构体,会浪费很大一块空间,采用指针传参只会浪费四个或者八个字节的空间。

6.位段

位段声明与结构体类似,不过位段的i结构体成员必须是int,unsigned int或者sign int

  • 位段可以很好的节省空间,但是会有跨平台的问题存在。
  • 位段的声明:
struct a
{
  int a:3;
    int b:4;
    int c:5;
    int d:4;
};  //如果上一个字节的bit位不够存放下一个变量,直接舍去此字节剩余的bit位,从下个字节开始存储,此端数据共为三个字节

:前是位段名,:后是bit位

例如_a只有两个bit位,就只能存两个bit的数据,有四种可能,00,01,10,11

如果超出此空间,多余的会舍去。

  • 给上面位段赋值,看看在内存中是怎样存储的
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

d65651b33b6e41029dbbd092faa14a0d.png

位段的应用


545643e9b3f34ef1822b453d93cc1a10.png

学过计算机网络的小伙伴应该都认识这个,这是一个报文头,在网络中进行传输信息对空间要求非常苛刻,每天数不清的数据在网络中进行传输,如果没有位段这种方式,那么会多浪费很多空间。

完结

创作不易,还请各位小伙伴多多点赞👍关注✨收藏⭐






































相关文章
|
21天前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
32 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
16天前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
87 14
|
21天前
|
存储 编译器 C语言
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
90 10
|
24天前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
42 6
|
25天前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
1月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
105 13
|
25天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
23天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
54 1
|
28天前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
28天前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
232 1