【C语言】自定义类型:结构体深入解析(一)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【C语言】自定义类型:结构体深入解析(一)
  🌈write in front :

✏️真正相信奇迹的家伙,本身和奇迹一样了不起啊!

欢迎大家关注🔍点赞👍收藏⭐️留言📝>希望看完我的文章对你有小小的帮助,如有错误,可以指出,让我们一起探讨学习交流,一起加油鸭。

📝前言

本小节,阿森继续和你一起学习什么是结构体?结构体类型的声明和创建,然后就是结构体的初始化,随即学习结构成员的访问操作符来更好的打印结构体的数据,当然还有匿名结构体类型,和结构的自引用。文章干货满满,接下来我们就学习一下结构体吧 😃!



🌠 什么是结构体?

结构体是一种用户定义的数据类型,它允许用户根据需要组合不同类型的变量。

struct Student 
{
  char name[20];
  int age;
  float score;
};

结构体通过struct关键字来定义,它允许将多个不同类型的数据元素组合在一起,这些数据元素称为结构体的成员。

🌅 结构体类型的声明和创建

  1. 结构体类型的声明
struct 结构体类型标签名 
{
  成员声明1;
  成员声明2;
  ...
};//分号不能丢

例如:

struct Student//此时只是声明了 Student 类型,
{       //但还没有创建任何 Student 类型的变量。
  int id;
  char name[20];
  float score;
};//分号不能丢
  1. 创建结构体类型的变量的语法如下:
struct 结构体类型名 变量名;

例如:

创建一个名为student1的学生结构体变量:
struct Student student1;
也可以在声明结构体类型的同时创建变量:
struct Stu
{
  char name[20];//名字
  int age;//年龄
  char sex[5];//性别
  char id[20];//学号
};
struct Stu s1;
struct Stu s2;

3.typedef关键字来为结构体类型定义别名,然后创建结构体变量

// 首先定义一个结构体类型
struct Student 
{
  int id;
  char name[20];
};

int main() 
{

  // 使用typedef为Student结构体类型定义一个别名StudentType
  typedef struct Student StudentType;  

  // 使用原结构体类型定义变量
  struct Student st1;

  // 使用新的类型别名定义变量 
  StudentType st2;

  // 访问结构体成员
  st1.id = 1001;
  st2.id = 1002;

  return 0;
}

typedef struct Student StudentType可以理解使用typedef把 struct Student重新取了一个名字 StudentType,此时这个 StudentTye就是一个类型,比如:int a;这个StudentTye就相当于int, StudentType st2;当然,这个 struct Student也可以理解为 int,所以也可以这么用 struct Student st1;

🌠 结构体变量的初始化

结构体变量的初始化主要有两种方式:

  1. 按照默认顺序初始化:

默认情况下,结构体成员的初始化顺序与它们在结构体定义中的顺序相同。

例如:

struct Stu
{
  char name[20];//名字
  int age;//年龄
  char sex[5];//性别
  char id[20];//学号
}p1;
struct Stu s1 = { "asenyaozixin",11,"男","2023012018" };
//定义结构体变量s2
  1. 指定顺序初始化:

可以通过在列表中指定成员名来指定成员的初始化顺序:

例如:

struct Stu
{
  char name[20];//名字
  int age;//年龄
  char sex[5];//性别
  char id[20];//学号
};
struct Stu s2 = { .age = 66,.id = "2023001001",.name = "ahuibuyiban",.sex = "nv" };

完整示例且打印:

struct Stu
{
  char name[20];//名字
  int age;//年龄
  char sex[5];//性别
  char id[20];//学号
};
int main()
{
  struct Stu s1 = { "asenyaozixin",11,"nan","2023012018" };//按照默认顺序初始化
  struct Stu s2 = { .age = 66,.id = "2024001001",.name = "ahuibuyiban",.sex = "nv" };//指定顺序初始化
  printf("%s %d %s %s\n", s1.name, s1.age, s1.sex, s1.id);
  printf("%s %d %s %s\n", s2.name, s2.age, s2.sex, s2.id);

  return 0;
}

打印结果:

🌅 结构成员访问操作符

结构成员访问操作符用于访问结构体中的成员变量。

结构体成员的直接访问

  1. 结构体成员的直接访问----点操作符(.)
    使⽤⽅式:结构体变量.成员名

使用点操作符可以访问结构的普通成员,例如:

struct Stu
{
  char name[20];
  int age;
  float score;
} s3 = { "熊大", 33, 66.0f }, s4 = {"熊二", 18, 100.0f};//全局变量

int main()
{
  struct Stu s1 = {"zhangsan", 20, 95.5f};//局部变量
  struct Stu s2 = {"lisi", 18, 87.5f};
  struct Stu s5 = {.score= 98.5f, .name="hehe", .age = 18};

  //. 结构成员访问操作符
  //结构体变量.成员名
  //
  printf("%s %d %f\n", s1.name, s1.age, s1.score);
  printf("%s %d %f\n", s2.name, s2.age, s2.score);
  printf("%s %d %f\n", s3.name, s3.age, s3.score);
  printf("%s %d %f\n", s4.name, s4.age, s4.score);
}

输出:

  1. 结构体成员的间接访问----箭头操作符(->)
    使⽤⽅式:结构体指针->成员名

结构体变量声明为结构体指针时,使用箭头操作符访问其成员:

struct Stu
{
  char name[20];
  int age;
  float score;
} s3 = { "熊大", 33, 66.0f }, s4 = {"熊二", 18, 100.0f};//全局变量

int main()
{
  struct Stu s1 = {"zhangsan", 20, 95.5f};//局部变量
  struct Stu s2 = {"lisi", 18, 87.5f};
  struct Stu s5 = {.score= 98.5f, .name="hehe", .age = 18};

  //结构体指针
  struct Stu* p1 = &s1;//取出s1的地址
  struct Stu* p2 = &s2;//取出s2的地址
  struct Stu* p3 = &s3;//取出s3的地址
  struct Stu* p4 = &s4;//取出s4的地址
  struct Stu* p5 = &s5;//取出s5的地址

  printf("%s %d %f\n", p1->name, p1->age, p1->score);
  printf("%s %d %f\n", p2->name, p2->age, p2->score);
  printf("%s %d %f\n", p3->name, p3->age, p3->score);
  printf("%s %d %f\n", p4->name, p4->age, p4->score);
  printf("%s %d %f\n", p5->name, p5->age, p5->score);

  //结构体指针->成员名
  
  return 0;
}

输出:


🌠 匿名结构体类型

匿名结构体类型就是没有给结构体类型起名字的结构体类型。

匿名结构体的定义方式:

struct 
{
  成员1 数据类型;
  成员2 数据类型;
  ...
} 变量名1, 变量名2, ...; 

例如:

struct
{
    int a;
    char b;
    float c;
} x;

匿名结构体的特点是:

  • 不需要给结构体起名字,定义时不指定结构体名称。
  • 只能在定义它的代码块内使用,不能在其他地方再次使用这个匿名结构体类型。

思考:下⾯的两个结构在声明的时候省略掉了结构体标签(tag),然后主函数里的p = &x的代码合法吗?

struct
{
  int a;
  char b;
  float c;
} x;

struct
{
  int a;
  char b;
  float c;
} *p;


int main()
{
  p = &x;//?代码合法吗?
  return 0;
}

输出没问题但有警告:

警告:

编译器会把上⾯的两个声明当成完全不同的两个类型,所以是⾮法的。

匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次。


🌅 结构的⾃引⽤

结构的自引用指的是结构体内部包含自己类型的指针成员,通过这个指针可以实现结构体之间的引用关系。

⾃引⽤⽅式:

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

// Node结构体包含一个指向Node结构体的指针next
// 通过next可以实现链表节点之间的引用关系

  • 思考1:
    在结构中包含⼀个类型为该结构本⾝的成员是否可以呢?
    ⽐如,定义⼀个链表的节点:
struct Node
{
 int data;
 struct Node next;
};

上述代码正确吗?如果正确,那 sizeof(struct Node) 是多少?

仔细分析,其实是不⾏的,因为⼀个结构体中再包含⼀个同类型的结构体变量,这样结构体变量的⼤⼩就会⽆穷的⼤,是不合理的。

代码运行:

图解分析:

  • 思考2:
    在结构体⾃引⽤使⽤的过程中,夹杂了typedef对匿名结构体类型重命名,也容易引⼊问题,看看下⾯的代码,可⾏吗?
typedef struct 
{
  int data;//存放数据
  Node* next;//存放写一个节点的地址
}Node;
int main()
{

  return 0;
}

运行:

分析:

首先使用typedef给前面匿名结构体起了别名Node,还不是类型,但是在typedef语句内,struct定义部分还没有结束,所以在struct内部使用Node声明next时,Node类型还未通typedef获得定义,仅仅是对匿名结构体的一个重命名,就提前使⽤Node类型来创建成员变量。


解决⽅案如下:定义结构体不要使⽤匿名结构体了

如下:先定义结构体:

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

再使用typedef给它起别名:

typedef struct Node Node;

或者一步完成:

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

🚩总结

这次阿森和你一起学习结构体的结构体类型的声明和创建,初始化,访问操作符,这是结构体基础知识,但阿森会慢慢和你一起学习,从基础到进阶。感谢你的收看,如果文章有错误,可以指出,我不胜感激,让我们一起学习交流,如果文章可以给你一个小小帮助,可以给博主点一个小小的赞😘

相关文章
|
13天前
|
存储 C语言
如何在 C 语言中实现结构体的深拷贝
在C语言中实现结构体的深拷贝,需要手动分配内存并逐个复制成员变量,确保新结构体与原结构体完全独立,避免浅拷贝导致的数据共享问题。具体方法包括使用 `malloc` 分配内存和 `memcpy` 或手动赋值。
23 10
|
13天前
|
安全 编译器 Linux
【c语言】轻松拿捏自定义类型
本文介绍了C语言中的三种自定义类型:结构体、联合体和枚举类型。结构体可以包含多个不同类型的成员,支持自引用和内存对齐。联合体的所有成员共享同一块内存,适用于判断机器的大小端。枚举类型用于列举固定值,增加代码的可读性和安全性。文中详细讲解了每种类型的声明、特点和使用方法,并提供了示例代码。
14 3
|
12天前
|
存储 大数据 编译器
C语言:结构体对齐规则
C语言中,结构体对齐规则是指编译器为了提高数据访问效率,会根据成员变量的类型对结构体中的成员进行内存对齐。通常遵循编译器默认的对齐方式或使用特定的对齐指令来优化结构体布局,以减少内存浪费并提升性能。
|
17天前
|
编译器 C语言
共用体和结构体在 C 语言中的优先级是怎样的
在C语言中,共用体(union)和结构体(struct)的优先级相同,它们都是用户自定义的数据类型,用于组合不同类型的数据。但是,共用体中的所有成员共享同一段内存,而结构体中的成员各自占用独立的内存空间。
|
17天前
|
存储 C语言
C语言:结构体与共用体的区别
C语言中,结构体(struct)和共用体(union)都用于组合不同类型的数据,但使用方式不同。结构体为每个成员分配独立的内存空间,而共用体的所有成员共享同一段内存,节省空间但需谨慎使用。
|
22天前
|
编译器 C语言 C++
C语言结构体
C语言结构体
21 5
|
22天前
|
编译器 Linux C语言
C语言 之 结构体超详细总结
C语言 之 结构体超详细总结
13 0
|
27天前
|
存储 编译器 Linux
深入C语言:探索结构体的奥秘
深入C语言:探索结构体的奥秘
|
27天前
|
存储 编译器 C语言
c语言回顾-结构体(2)(下)
c语言回顾-结构体(2)(下)
28 0
|
27天前
|
存储 编译器 程序员
c语言回顾-结构体(2)(上)
c语言回顾-结构体(2)(上)
27 0

推荐镜像

更多