【C语言】一篇让你彻底吃透(结构体与结构体位段)(上)

简介: 【C语言】一篇让你彻底吃透(结构体与结构体位段)(上)

本章重点

主要讲解结构体和位移动的使用和定义与声明,并且结构体和位段在内存中是如何存储的。


结构体



结构体类型的声明


结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。


例如用结构体描述一个学生:


struct Stu
{
    //结构体成员变量
   char name[20];//名字
   int age;//年龄
   char sex[5];//性别
   char id[20];//学号
}; //分号不能丢


  1. struct 结构体关键字
  2. stu结构体标签 (标签可以自己随便起)
  3. struct stu - 结构体类型
  4. 结构的成员可以是标量、数组、指针,甚至是其他结构体。


结构体特殊的声明


在声明结构的时候,可以不完全的声明,但是这样只能调用一次。


匿名结构体类型

只能调用一次,因为没有结构体标签


//匿名结构体类型  
struct
{
  int a;
  char b;
  float c;
}x; //(但是这样写只能调用一次x,因为没有结构体标签)


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


有了结构体类型,那如何定义变量和初始化呢,其实很简单。


  • 结构体定义:


struct stu
{
  char name[20];//名字
  int age;//年龄
  char sex[5];//性别
  char id[20];//学号
}s1,s2,s3;    全局变量的定义
struct stu s4;  全局变量的定义
int main()
{
  struct stu s5;  局部变量定义
  struct stu s6;  局部变量定义
  return 0;
}


如果结构体名字过长,我们也可以typedef一下,但是typedef时注意,想在此地方加全局变量是不允许的,如果此时想要创造全局变量应该像上代码s4一样创造。


4a52e9c280bf46859599d687daa7c2ad.png


  • 结构体初始化


struct stu
{
  char name[20];//名字
  int age;//年龄
  char sex[5];//性别
  char id[20];//学号
}s1 = { "wangwu",25,"sex","2022333" }; 
struct stu s1 = { "lihua",18,"sex","2022111" }; //全局变量的初始化
int main()
{
  struct stu s2 = { "lisi",20,"sex","2022222" };//局部变量初始化
  return 0;
}


结构体成员的访问


结构体变量如何访问成员?


结构变量的成员是通过点操作符(.)访问的。点操作符接受两个操作数。

结构变量的成员也可以通过->箭头来访问。


那(.)和->到底使用那个呢?

  • 点(.)是用于结构体变量访问成员
  • 箭头(->)是用于结构体指针访问成员。


  • 点(.)是用于结构体变量访问成员


#include<stdio.h>
struct stu
{
  char name[20];//名字
  int age;//年龄
  char sex[5];//性别
  char id[20];//学号
};
void test1(struct stu q1)
{
  //通过 . 来访问
  printf("%s\n", q1.name);
  printf("%d\n", q1.age);
  printf("%s\n", q1.sex);
  printf("%s\n", q1.id);
}
int main()
{
  struct stu s1 = { "lisi",20,"sex","2022222" };//局部变量初始化
  test1(s1);
  return 0;
}


  • 箭头(->)是用于结构体指针访问成员。


#include<stdio.h>
struct stu
{
  char name[20];//名字
  int age;//年龄
  char sex[5];//性别
  char id[20];//学号
};
void test2(struct stu* q1)
{
  //通过 . 来访问
  printf("%s\n", q1->name);
  printf("%d\n", q1->age);
  printf("%s\n", q1->sex);
  printf("%s\n", q1->id);
}
int main()
{
  struct stu s1 = { "lisi",20,"sex","2022222" };//局部变量初始化
  test2(&s1);
  return 0;
}


结构的自引用


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


答案是 可以的。

但是必须写成指针的形式。如果写成以下这样是错误的,会一直套娃下去,根本不知道该结构体大小是多少


  • 错误的写法


struct Node
{
  int data;
  struct Node next;
};


  • 正确的写法应该写成指针的形式


struct Node
{
  int data;
  struct Node* next;
};


结构体内存对齐


我们已经掌握了结构体的基本使用了。

现在我们深入讨论一个问题:计算结构体的大小。


  • 看看以下代码输出的是什么


struct S1
{
  int a;
  char c;
};
int main()
{
  int ret = sizeof(struct S1);
  printf("%d\n", ret);
  return 0;
}


很多人一开始以为是5,但并不是的。

答案是8,那为什么呢,这就与结构体内存对齐相关了


  • 如何计算结构体内存?


首先得掌握结构体的对齐规则:

1.结构体的第一个成员永远都放在0偏移处

2.从第二个成员开始,以后的每个成员都要对齐到某个(对齐数)的整数倍地址处.(取对齐数较小值)

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

备注:

VS 环境下 默认对齐数是8

gcc 环境下 没有默认对齐数,没有默认对齐数时,对齐数就是成员自身的大小

3.当成员全部存放进去后, 结构体的总大小必须是,所有成员的对齐数中最大对齐数的整数倍如果不够,则浪费空间对齐.

4.如果嵌套了结构体,嵌套的结构体成员要对齐到自己成员的最大对齐数的整数倍处,整个结构体的大小,必须是最大对齐数的整数倍,最大对齐数包含中嵌套的结构体成员中的对齐数


我们直接上练习理解


  • 练习 1 (sizeof(struct S1)输出结果是什么)


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


答案是->12

24c4487d4dec44af8246a990da78dcd9.png

  • 练习 2 (sizeof(struct S2)输出结果是什么)


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


答案是->8

0711644ccce14e47b2e7362c2329f536.png


目录
相关文章
|
2月前
|
网络协议 编译器 Linux
【C语言】结构体内存对齐:热门面试话题
【C语言】结构体内存对齐:热门面试话题
|
25天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
63 16
|
2月前
|
存储 C语言
如何在 C 语言中实现结构体的深拷贝
在C语言中实现结构体的深拷贝,需要手动分配内存并逐个复制成员变量,确保新结构体与原结构体完全独立,避免浅拷贝导致的数据共享问题。具体方法包括使用 `malloc` 分配内存和 `memcpy` 或手动赋值。
45 10
|
2月前
|
存储 大数据 编译器
C语言:结构体对齐规则
C语言中,结构体对齐规则是指编译器为了提高数据访问效率,会根据成员变量的类型对结构体中的成员进行内存对齐。通常遵循编译器默认的对齐方式或使用特定的对齐指令来优化结构体布局,以减少内存浪费并提升性能。
|
2月前
|
编译器 C语言
共用体和结构体在 C 语言中的优先级是怎样的
在C语言中,共用体(union)和结构体(struct)的优先级相同,它们都是用户自定义的数据类型,用于组合不同类型的数据。但是,共用体中的所有成员共享同一段内存,而结构体中的成员各自占用独立的内存空间。
|
2月前
|
存储 C语言
C语言:结构体与共用体的区别
C语言中,结构体(struct)和共用体(union)都用于组合不同类型的数据,但使用方式不同。结构体为每个成员分配独立的内存空间,而共用体的所有成员共享同一段内存,节省空间但需谨慎使用。
|
2月前
|
编译器 C语言 C++
C语言结构体
C语言结构体
28 5
|
2月前
|
C语言
C语言结构体链式结构之有头单链表
文章提供了一个C语言实现的有头单链表的完整代码,包括创建链表、插入、删除和打印等基本操作。
31 1
|
2月前
|
C语言
初识C语言6——结构体
初识C语言6——结构体
18 3
|
2月前
|
存储 编译器 C语言
【C语言】探索结构体基础知识:简明概要
【C语言】探索结构体基础知识:简明概要