C语言结构体漫谈:从平凡中见不平凡

大家好,这里是小编的博客频道
小编的博客:就爱学编程

很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!!

本文目录

  • 引言
  • 正文
  • 《1》 结构体的两种声明
      • 一、结构体的定义
      • 二、全局结构体变量
      • 三、局部结构体变量
      • 四、匿名结构体与全局/局部变量
  • 《2》typedef对结构体类型进行重命名
      • 一、基本语法
      • 二、作用与优势
      • 三、示例说明
  • 《3》 结构体的初始化和访问
      • 1. 声明时初始化
      • 2. **后续初始化**
      • 3.访问结构体成员
  • 《4》 结构体的内存对齐和修改默认对其数的方法
      • 一、结构体与内存对齐的基本概念
      • 二、结构体内存对齐的规则
      • 三、为什么存在内存对齐
      • 四、如何修改默认对齐数
        • 1.使用#pragma pack
        • 2.使用__attribute__((packed))
  • 《5》结构体传参
      • 一、通过值传递结构体
      • 二、通过指针传递结构体
      • 三、返回结构体
        • 3.1 返回结构体值
        • 3.2 返回结构体指针
  • 快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!

引言

在C语言中,结构体(struct)是一种用户自定义的数据类型,它允许将多个不同类型的数据项组合成一个单一的类型。结构体是编程中组织相关数据的有效方式,尤其在处理复杂数据时显得尤为重要。以下是对C语言结构体基础知识的详细介绍,一起来看看吧!!

在这里插入图片描述


那接下来就让我们开始遨游在知识的海洋!

正文


在C语言中,当结构体被定义后,可以在全局作用域或局部作用域(如函数内部)中声明其变量。这些结构体变量的作用域和生命周期会根据它们是在全局还是局部声明的而有所不同。下面小编将详细解释全局变量、局部变量以及匿名声明与结构体之间的关系,特别是在主函数内的区别。

《1》 结构体的两种声明


一、结构体的定义

首先,我们需要定义一个结构体。例如:

struct MyStruct {int a;float b;
};

这里我们定义了一个名为MyStruct的结构体,它包含两个成员:一个整型a和一个浮点型b


二、全局结构体变量

如果在所有函数之外声明一个结构体变量,那么它就是全局的。全局结构体变量在整个程序的生命周期内都有效,并且可以被任何函数访问。例如:

// 全局作用域中声明结构体变量
struct MyStruct globalVar;int main() {// 可以在main函数中访问globalVarglobalVar.a = 10;globalVar.b = 3.14;// ... 其他代码
}

在这个例子中,globalVar是一个全局结构体变量,它在整个程序中都是可见的,包括在main函数内。


三、局部结构体变量

如果在某个函数内部声明一个结构体变量,那么它就是局部的。局部结构体变量只在声明它的函数内部有效,一旦函数执行完毕,该变量就会被销毁。例如:

int main() {// 局部作用域中声明结构体变量struct MyStruct localVar;localVar.a = 20;localVar.b = 6.28;// localVar只能在main函数内部使用// ... 其他代码
}

在这个例子中,localVar是一个局部结构体变量,它只能在main函数内部被访问和使用。


四、匿名结构体与全局/局部变量

在C语言中,还可以声明匿名结构体变量。匿名结构体是没有名称的结构体类型,通常用于只需要一个结构体实例的情况。匿名结构体变量的声明方式与全局或局部变量类似,只是没有给出结构体的名称。例如:

// 在全局作用域中声明匿名结构体变量
struct {int x;int y;
} globalAnonymousVar;int main() {// 在局部作用域中声明另一个匿名结构体变量(注意:这是另一个不同的类型)struct {int m;int n;} localAnonymousVar;globalAnonymousVar.x = 1;globalAnonymousVar.y = 2;localAnonymousVar.m = 3;localAnonymousVar.n = 4;// 注意:globalAnonymousVar和localAnonymousVar是不同类型的变量// 因此不能相互赋值或比较// ... 其他代码
}

在这个例子中,globalAnonymousVarlocalAnonymousVar分别是全局和局部的匿名结构体变量。需要注意的是,由于它们是匿名的且定义不同,因此它们是两种完全不同的类型,不能相互赋值或比较。

  • 全局结构体变量在整个程序生命周期内有效,可以被任何函数访问。
  • 局部结构体变量只在声明它的函数内部有效,函数执行完毕后会被销毁。
  • 匿名结构体变量没有名称的结构体类型,通常用于单个实例的情况。全局和局部的匿名结构体变量是两种不同的类型。

希望以上内容能够帮助宝子们理解C语言中结构体与全局变量、局部变量以及匿名声明之间的关系。


typedef是C语言中的一个关键字,它主要用于为数据类型定义新的名称(别名),这包括基本数据类型、引用类型以及自定义的数据类型。在结构体(struct)的使用中,typedef的作用尤为显著,因为它可以简化结构体的声明和使用,提高代码的可读性和可维护性。以下是对typedef对结构体进行重命名的详细介绍.

《2》typedef对结构体类型进行重命名


一、基本语法

typedef的基本语法如下:

typedef 原有类型 新类型名;

当用于结构体时,可以这样写:

typedef struct {成员列表;
} 新类型名;

或者先定义结构体,再用typedef为其命名:

struct 旧类型名 {成员列表;
};
typedef struct 旧类型名 新类型名;

二、作用与优势

  1. 简化声明:使用typedef可以为复杂的结构体类型定义一个简短且易于理解的新名字,从而简化变量的声明。例如,对于包含多个成员的结构体,直接使用其原始类型声明变量可能会显得冗长,而使用typedef定义的新类型名则可以使声明更加简洁明了。
  1. 提高可读性:通过为结构体类型定义具有描述性的新名字,可以提高代码的可读性。这些新名字通常能够更直观地反映结构体的用途或内容,从而使代码更容易被理解和维护。
  1. 便于修改:如果需要在程序中更改结构体的定义,只需修改结构体本身的定义即可,而不必修改所有使用该结构体的变量声明。这是因为这些变量声明使用的是由typedef定义的新类型名,而不是结构体的原始类型名。因此,使用typedef可以降低因修改结构体定义而导致的代码修改量。

三、示例说明

以下是一个使用typedef对结构体进行重命名的示例:

#include <stdio.h>// 使用typedef定义一个新的结构体类型Point3D
typedef struct {int x;int y;int z;
} Point3D;int main() {// 使用新类型名Point3D声明变量pPoint3D p = {1, 2, 3};// 打印变量p的成员值printf("x: %d, y: %d, z: %d
", p.x, p.y, p.z);return 0;
}

在这个示例中,我们首先使用typedef定义了一个新的结构体类型Point3D,该结构体包含三个整型成员xyz。然后,我们在main函数中使用新类型名Point3D声明了一个变量p,并初始化了它的成员值。最后,我们打印了变量p的成员值以验证其正确性。

注意:

  1. 在使用typedef对结构体进行重命名时,应确保新类型名的唯一性和描述性,以避免与其他类型名冲突并提高代码的可读性。
  1. 如果结构体中包含指向自身的指针成员(即自引用),则需要特别注意typedef的使用方式。在这种情况下,可以先定义结构体的匿名类型,然后使用typedef为该类型命名;或者在定义结构体的同时直接使用typedef为其命名,并在结构体内部使用struct关键字加上新类型名来声明指向自身的指针成员。

综上所述:

  • typedef是C语言中一个非常有用的关键字,它可以极大地简化结构体的声明和使用,提高代码的可读性和可维护性。

当然!在C语言中,结构体(struct)是一种用户自定义的数据类型,允许将不同类型的数据组合成一个单一的类型。链表是一种常见的数据结构,它由一系列节点组成,每个节点包含数据部分和指向下一个节点的指针。通过结构体,我们可以方便地实现链表。

下面是一篇关于如何使用C语言的结构体来实现链表的详细介绍。

《3》 结构体的初始化和访问


1. 声明时初始化

我们可以在声明结构体变量的同时对其进行初始化。这通常使用花括号{}来指定每个成员的初值。

struct Student student1 = {"Alice", 20, 95.5};

在这个例子中,我们创建了一个名为student1Student结构体变量,并在声明时将其成员初始化为"Alice"2095.5


2. 后续初始化

如果我们在声明时没有初始化结构体变量,那么可以在后续的代码中逐个设置其成员的值。

struct Student student2;
strcpy(student2.name, "Bob");  // 使用strcpy函数复制字符串到字符数组
student2.age = 22;
student2.grade = 88.0;

注意:

  • 对于字符数组类型的成员,我们不能直接赋值(如student2.name = "Bob";),因为这样会尝试将一个字符串常量的地址赋给字符数组,而不是将字符串内容复制到数组中。因此,我们使用strcpy函数来复制字符串。

3.访问结构体成员

一旦我们有了结构体变量,就可以通过点运算符.来访问其成员。以下是一些示例:

printf("Name: %s
", student1.name);
printf("Age: %d
", student1.age);
printf("Grade: %.2f
", student1.grade);

在这个例子中,我们使用点运算符.来访问student1的各个成员,并将它们打印到控制台上。


《4》 结构体的内存对齐和修改默认对其数的方法

以下是一篇关于结构体的内存对齐和修改默认对齐方法的详细介绍.


一、结构体与内存对齐的基本概念

在编程中,结构体(Structure)是一种可以存储不同类型数据项的复合数据类型。它是一种用户自定义的数据类型,用于封装一组相关联的不同类型的数据项。结构体是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

内存对齐是指数据在内存中按照一定的规则进行排列,以提高内存访问的效率。对于结构体来说,内存对齐意味着其成员变量在内存中的地址需要满足特定的对齐要求。这种对齐通常是由编译器自动处理的,但程序员也可以通过特定指令进行修改。


二、结构体内存对齐的规则

  1. 结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处。
  1. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。这个对齐数通常是编译器默认的一个对齐数与该成员大小的较小值。不同的编译器和平台可能有不同的默认对齐数。
  1. 结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数,取其中最大的一个)的整数倍。这是为了确保结构体在内存中的布局是紧凑且高效的。
  1. 如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。

三、为什么存在内存对齐

内存对齐的存在主要有以下几个原因:

  1. 提高内存访问效率:在许多计算机架构中,内存的访问速度是有限的。如果数据在内存中的位置是随机的,那么CPU需要花费额外的时间来寻找数据,这被称为内存访问延迟。然而,如果数据按照特定的对齐规则进行存储,CPU的内存控制器就可以更有效地预取数据,从而减少内存访问延迟。
  1. 提高硬件效率:许多现代CPU都有专门为对齐数据而设计的内部机制。例如,一些CPU具有专门的对齐引擎,可以更快地处理对齐的数据。如果数据没有对齐,CPU可能需要进行多次访问内存才能获取到完整的数据,这会降低CPU的效率。
  1. 减少数据依赖:在某些情况下,如果数据没有对齐,可能会导致一些特定的CPU指令无法使用,从而增加了数据的依赖性。这可能会使得程序的并行度降低,从而影响程序的性能。
  1. 提高程序的稳定性:在某些情况下,不对齐的内存访问可能会导致硬件异常或者程序崩溃。因此,编程时进行内存对齐不仅可以提高程序的性能,还可以提高程序的稳定性和可维护性。

四、如何修改默认对齐数

在C语言中,可以使用#pragma pack__attribute__((packed))来改变结构体的对齐方式以减少填充字节。以下是两种方法的示例:

1.使用#pragma pack
#include <stdio.h>
#include <stddef.h>// 将对齐设置为1字节
#pragma pack(push, 1)
typedef struct {char c1;       // 1 byteint i;         // 4 bytes, but aligned to 1 byte boundary herechar c2;       // 1 byte
} S1;
#pragma pack(pop)  // 恢复默认对齐设置int main() {printf("%zu
", sizeof(S1));  // 输出结果为6,因为没有额外的填充字节return 0;
}

在这个例子中,使用了#pragma pack(push, 1)将当前的对齐设置保存在栈中,并设置新的对齐方式为1字节。这样,结构体S1的成员就会紧密排列在一起,没有额外的填充字节。使用完之后,通过#pragma pack(pop)恢复之前的对齐设置。

2.使用__attribute__((packed))

这种方法适用于GCC和一些兼容的编译器。它告诉编译器不要为结构体的成员进行任何额外的对齐填充。

#include <stdio.h>
#include <stddef.h>typedef struct __attribute__((packed)) {char c1;       // 1 byteint i;         // 4 bytes, but packed tightly with no paddingchar c2;       // 1 byte
} S2;int main() {printf("%zu
", sizeof(S2));  // 输出结果为6,同样没有额外的填充字节return 0;
}

需要注意的是:

  • 虽然这两种方法可以减少结构体的总大小,但它们可能会降低数据访问的效率。因为未对齐的数据访问可能需要更多的内存操作,这在某些平台上可能会有较大的性能影响。

结构体的内存对齐是提高内存访问效率和程序稳定性的重要手段。了解并掌握结构体内存对齐的规则和修改默认对齐数的方法对于优化程序性能和资源利用具有重要意义。在实际编程中,应根据具体需求和平台特性选择合适的对齐方式和策略。


《5》结构体传参

一、通过值传递结构体

最简单的方式是通过值传递结构体到函数中。这意味着函数会接收到结构体的一个副本,对副本的任何修改都不会影响原始结构体。

#include <stdio.h>
#include <string.h>struct Person {char name[50];int age;float height;
};void printPerson(struct Person p) {printf("Name: %s
", p.name);printf("Age: %d
", p.age);printf("Height: %.2f
", p.height);
}int main() {struct Person person1 = {"Alice", 30, 5.7};printPerson(person1); // 通过值传递return 0;
}

缺点

  • 如果结构体很大,通过值传递会导致大量的内存复制操作,从而降低程序效率。

二、通过指针传递结构体

更常见且高效的方法是通过指针传递结构体。这样,函数接收的是指向结构体的指针,可以直接访问和修改原始数据。

#include <stdio.h>
#include <string.h>struct Person {char name[50];int age;float height;
};void printPerson(struct Person *p) {printf("Name: %s
", p->name);printf("Age: %d
", p->age);printf("Height: %.2f
", p->height);
}void modifyPerson(struct Person *p) {strcpy(p->name, "Bob");p->age = 25;p->height = 6.0;
}int main() {struct Person person1 = {"Alice", 30, 5.7};printPerson(&person1); // 通过指针传递modifyPerson(&person1); // 修改结构体内容printPerson(&person1); // 再次打印以查看修改结果return 0;
}

优点

  • 避免了大结构体的复制开销。
  • 可以直接修改原始结构体中的数据。

在某些情况下,你可能希望从函数中返回一个结构体。这同样可以通过值和指针两种方式来实现。

三、返回结构体

3.1 返回结构体值
#include <stdio.h>struct Point {int x;int y;
};struct Point createPoint(int x, int y) {struct Point p;p.x = x;p.y = y;return p;
}int main() {struct Point p1 = createPoint(10, 20);printf("Point created: (%d, %d)
", p1.x, p1.y);return 0;
}

对于小型结构体,这种方式是可行的,但对于大型结构体,返回值可能会导致性能问题,因为涉及到结构体的复制。

3.2 返回结构体指针
#include <stdio.h>
#include <stdlib.h>struct Point {int x;int y;
};struct Point* createPoint(int x, int y) {struct Point *p = (struct Point*)malloc(sizeof(struct Point));if (p != NULL) {p->x = x;p->y = y;}return p;
}int main() {struct Point *p1 = createPoint(10, 20);if (p1 != NULL) {printf("Point created: (%d, %d)
", p1->x, p1->y);free(p1); // 不要忘记释放动态分配的内存}return 0;
}

这种方法适用于大型结构体或需要在函数外部持续使用结构体的情况,但需要注意内存管理,确保在使用完毕后释放动态分配的内存。

  • 通过值传递:简单直观,但不适合大型结构体,因为会有较大的内存开销。
  • 通过指针传递:高效且灵活,可以直接修改原始数据,是推荐的方法。
  • 返回结构体:小型结构体可以通过值返回,大型结构体建议通过指针返回并注意内存管理。

理解并掌握这些结构体传参方式,将有助于宝子们编写更高效、灵活的C语言程序。


快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/2850.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

lwip单网卡多ip的实现

1、今天要实现lwip的多个ip配置&#xff0c;本来以为需要自己修改很多核心代码 2、查阅资料才发现&#xff0c;lwip已经把接口留出来了 /** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type) * to a filter function that returns the correct neti…

MySQL NaviCat 安装及配置教程(Windows)【安装】

文章目录 一、 MySQL 下载 1. 官网下载2. 其它渠道 二、 MySQL 安装三、 MySQL 验证及配置四、 NaviCat 下载 1. 官网下载2. 其它渠道 五、 NaviCat 安装六、 NaviCat 逆向工程 软件 / 环境安装及配置目录 一、 MySQL 下载 1. 官网下载 安装地址&#xff1a;https://www.m…

HarmonyOS Next 实现登录注册页面(ARKTS) 并使用Springboot作为后端提供接口

1. HarmonyOS next ArkTS ArkTS围绕应用开发在 TypeScript &#xff08;简称TS&#xff09;生态基础上做了进一步扩展&#xff0c;继承了TS的所有特性&#xff0c;是TS的超集 ArkTS在TS的基础上扩展了struct和很多的装饰器以达到描述UI和状态管理的目的 以下代码是一个基于…

Web第一次作业

主页: <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>主页</title> </head> <body> <h1>你好&#xff01; 来到我的网站</h1> <p><a href"login…

大疆最新款无人机发布,可照亮百米之外目标

近日&#xff0c;DJI 大疆发布全新小型智能多光旗舰 DJI Matrice 4 系列&#xff0c;包含 Matrice 4T 和 Matrice 4E 两款机型。DJI Matrice 4E 价格为27888 元起&#xff0c;DJI Matrice 4T价格为38888元起。 图片来源&#xff1a;大疆官网 DJI Matrice 4E DJI Matrice 4T D…

掌握C语言内存布局:数据存储的智慧之旅

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 目录 引言正文一、数据类型介绍1.内置类型2.自定义…

图论的起点——七桥问题

普瑞格尔河从古堡哥尼斯堡市中心流过&#xff0c;河中有小岛两座&#xff0c;筑有7座古桥&#xff0c;哥尼斯堡人杰地灵&#xff0c;市民普遍爱好数学。1736年&#xff0c;该市一名市民向大数学家Euler提出如下的所谓“七桥问题”&#xff1a; 从家里出发&#xff0c;7座桥每桥…

ubuntu20.04安装MySQL5.7

deb安装 下载deb文件并配置 wget https://repo.mysql.com//mysql-apt-config_0.8.12-1_all.deb sudo dpkg -i mysql-apt-config_0.8.12-1_all.deb我使用xshell可以正常。 这个弹出框里&#xff0c;选择的是“ubuntu bionic”。(在终端工具上&#xff0c;有可能显示不了选项)【…

openharmony标准系统方案之瑞芯微RK3568移植案例

标准系统方案之瑞芯微RK3568移植案例 ​本文章是基于瑞芯微RK3568芯片的DAYU200开发板&#xff0c;进行标准系统相关功能的移植&#xff0c;主要包括产品配置添加&#xff0c;内核启动、升级&#xff0c;音频ADM化&#xff0c;Camera&#xff0c;TP&#xff0c;LCD&#xff0c…

【C语言】_求字符串长度函数strlen

目录 1. 函数声明及功能 2. 注意事项 3. 模拟实现 3.1 方式1&#xff1a;计数器方式 3.2 方式2&#xff1a;指针-指针方式 3.3 方式3&#xff1a;递归方式&#xff08;不创建临时变量计数器方式&#xff09; 4. strlen相关例题 1. 函数声明及功能 size_t strlen ( cons…

【大前端】Vue3 工程化项目使用详解

目录 一、前言 二、前置准备 2.1 环境准备 2.1.1 create-vue功能 2.1.2 nodejs环境 2.1.3 配置nodejs的环境变量 2.1.4 更换安装包的源 三、工程化项目创建与启动过程 3.1 创建工程化项目 3.2 项目初始化 3.3 项目启动 3.4 核心文件说明 四、VUE两种不同的API风格 …

微软开源AI Agent AutoGen 详解

AutoGen是微软发布的一个用于构建AI Agent系统的开源框架,旨在简化事件驱动、分布式、可扩展和弹性Agent应用程序的创建过程。 开源地址: GitHub - microsoft/autogen: A programming framework for agentic AI 🤖 PyPi: autogen-agentchat Discord: https://aka.ms/auto…

cursor重构谷粒商城02——30分钟构建图书管理系统【cursor使用教程番外篇】

前言&#xff1a;这个系列将使用最前沿的cursor作为辅助编程工具&#xff0c;来快速开发一些基础的编程项目。目的是为了在真实项目中&#xff0c;帮助初级程序员快速进阶&#xff0c;以最快的速度&#xff0c;效率&#xff0c;快速进阶到中高阶程序员。 本项目将基于谷粒商城…

[Qualcomm]Qualcomm MDM9607 SDK代码下载操作说明

登录Qualcomm CreatePoing Qualcomm CreatePointhttps://createpoint.qti.qua

【15】Word:互联网发展状况❗

目录 题目​ NO2 NO3 NO4 NO5 NO6 NO7.8.9 NO7 NO8 NO9 NO10 题目 NO2 布局→页面设置→纸张&#xff1a;A4→页边距&#xff1a;上下左右→版式&#xff1a;页眉/页脚页码范围&#xff1a;多页&#xff1a;对称页边距→内侧/外侧→装订线 NO3 首先为文档应用内置…

ROS1学习记录

我使用的是ubuntu20.04下的ROS Noetic版本&#xff0c;是ROS 1 的最后一个长期支持&#xff08;LTS&#xff09;版本&#xff0c;将于2025年5月停止维护 一&#xff0c;Linux系统基本操作 ctrlaltt快速打开终端 1&#xff0c;pwd命令 查看当前终端所在路径 使用方式&#…

Go Ebiten小游戏开发:贪吃蛇

贪吃蛇是一款经典的小游戏&#xff0c;玩法简单却充满乐趣。本文将介绍如何使用 Go 语言和 Ebiten 游戏引擎开发一个简单的贪吃蛇游戏。通过这个项目&#xff0c;你可以学习到游戏开发的基本流程、Ebiten 的使用方法以及如何用 Go 实现游戏逻辑。 项目简介 贪吃蛇的核心玩法是…

ASP.NET Core - .NET 6 以上版本的入口文件

ASP.NET Core - .NET 6 以上版本的入口文件 自从.NET 6 开始&#xff0c;微软对应用的入口文件进行了调整&#xff0c;移除了 Main 方法和 Startup 文件&#xff0c;使用顶级语句的写法&#xff0c;将应用初始化的相关配置和操作全部集中在 Program.cs 文件中&#xff0c;如下&…

Chapter1:初见C#

参考书籍&#xff1a;《C#边做边学》&#xff1b; 1.初见C# 1.1 C#简介 C # {\rm C\#} C#编写了许多完成常用功能的程序放在系统中&#xff0c;把系统中包含的内容按功能分成多个部分&#xff0c;每部分放在一个命名空间中&#xff0c;导入命名空间语法格式如下&#xff1a; /…

React封装倒计时按钮

背景 在开发过程中&#xff0c;经常需要使用到倒计时的场景&#xff0c;当用户点击后&#xff0c;按钮进行倒计时&#xff0c;然后等待邮件或者短信发送&#xff0c;每次都写重复代码&#xff0c;会让代码显得臃肿&#xff0c;所以封装一个组件来减少耦合 创建一个倒计时组件…