浅析开源内存数据库Fastdb

介绍:

Fastdb是免费开源内存数据库,其优秀的性能,和简洁的C++代码,让我学习使用过程中收益颇多,但是国内中文相关研究的文章相当稀少,外文我查询相当不便。有兴趣的朋友可以通过以下网站访问:Main Memory Object-Relational Database Management System,相关文档详见:FastDB Main Memory Database Management System。本文将以Windows版本C++版本号3.76为基础进行开发和测试,听说有4.14的版本但是我没有办法获取,有获得新版本的朋友不妨能发我一份学习,我的邮箱:lyfwwb@163.com,在此先行感谢!本文将记录学习相关过程中心得和一些功能分析,希望自己不会忘记曾经使用过的历史和自己改造过程。借此机会给那些和我一样想用的朋友又碰到一样问题的人提供一些思路和方法。希望有人可以给我更好更完善的资料系统学习。很多人认为Fastdb只能本机上进行数据库操作,其实Fastdb在3.76版本中已经提供简单服务端/客户端功能了,有C++编程能力的可以实现更多的功能。框架作者已经做得很好了。

下面是Fastdb官方的介绍译文:

FastDB是一个高效的主存数据库系统,具有实时功能和方便的C++接口。FastDB不支持客户端-服务器体系结构,所有使用FastDB数据库的应用程序都应该在同一主机上运行。FastDB针对具有主导读取访问模式的应用程序进行了优化。通过消除数据传输开销和非常有效的锁定实现,可以提供高速的查询执行。数据库文件被映射到与数据库一起工作的每个应用程序的虚拟内存空间。因此,查询是在应用程序的上下文中执行的,不需要上下文切换和数据传输。并发数据库访问的同步是通过原子指令在FastDB中实现的,几乎不增加查询处理的开销。FastDB假设整个数据库都存在于RAM中,并根据这一假设优化搜索算法和结构。此外,FastDB没有数据库缓冲区管理引起的开销,并且不需要在数据库文件和缓冲池之间进行数据传输。这就是为什么FastDB的工作速度要比所有数据都缓存在缓冲池中的传统数据库快得多。

FastDB支持事务处理、在线备份和系统崩溃后的自动恢复。事务提交协议基于影子根页算法,执行数据库的原子更新。恢复可以非常快速地完成,为关键应用程序提供高可用性。此外,事务日志的消除提高了整个系统的性能,并使系统资源得到更有效的利用。

FastDB是一个面向应用程序的数据库。数据库表是使用有关应用程序类的信息构建的。FastDB支持自动方案评估,允许您只在一个地方进行更改——在应用程序类中。FastDB为从数据库中检索数据提供了一个灵活方便的接口。使用类似SQL的查询语言来指定查询。非原子字段、嵌套数组、用户定义的类型和方法、直接的对象间引用等后关系功能简化了数据库应用程序的设计,提高了它们的效率。

尽管FastDB是在假设数据库作为一个整体适合计算机的物理内存的情况下进行优化的,但也可以将其与数据库一起使用,因为数据库的大小超过了系统中物理内存的大小。在最后一种情况下,标准操作系统交换机制将起作用。但所有FastDB搜索算法和结构都是在所有数据都驻留在内存中的假设下进行优化的,因此交换数据的效率不会很高。

功能模块的分析与介绍

1、查询语言介绍:

FastDB支持具有类似SQL语法的查询语言。FastDB使用的符号在面向对象编程中比在关系数据库中更受欢迎。表行被视为对象实例,表是这些对象的类。与SQL不同,FastDB面向的是使用对象,而不是SQL元组。因此,每次查询执行的结果都是一个类的一组对象。FastDB查询语言与标准SQL的主要区别在于:

1、 没有几个表和嵌套子查询的联接。查询总是从一个表中返回一组对象。

2、 标准C类型用于原子表列。

3、 除了空引用之外,没有空值。我完全同意C.J.Date对三值逻辑的批评,以及他使用默认值的建议。

4、 结构和数组可以用作记录组件。提供了一个特殊的存在量化器来定位数组中的元素。

5、 可以为表记录(对象)以及记录组件定义无参数用户方法。

6、 应用程序可以定义(只有)一个字符串或数字参数的用户函数。

7、 支持对象之间的引用,包括对反向引用的自动支持。

8、 从后面开始的构造使用引用执行递归记录遍历。

9、 由于查询语言被深度集成到C++类中,因此对语言标识符和关键字都使用了区分大小写的模式。

10、 没有完成整数和浮点类型到字符串表示形式的隐式转换。如果需要这样的转换,就必须明确地进行。

下面以类似BNF的符号表示法规定了FastDB查询语言搜索谓词的语法:

标识符区分大小写,以a-z、a-z、'_'或'$'字符开头,仅包含a-z、a-z、0-9、'_‘或'$‘字符,并且不重复SQL保留字。

保留字列表 
absandascbetweenby
currentdescescapeexistsfalse
firstfollowfromininteger
islengthlikelastlower
matchnotnullorreal
startstringtrueupper

也可以使用ANSI标准注释。双连字符后直到行尾的所有字符都将被忽略。

FastDB通过支持位操作来扩展ANSI标准SQL操作。运算符and/or不仅可以应用于布尔操作数,还可以应用于整数类型的操作数。将and/or运算符应用于整数操作数的结果是通过位and/位or运算设置位的整数值。位操作可以用于小集合的有效实现。此外,对于整数和浮点类型,FastDB也支持对幂运算(x^y)的引用。

2、结构

FastDB接受结构作为记录的组成部分。可以使用标准点表示法访问结构的字段如 :company.address.city

结构字段可以按规范的顺序进行索引和使用。结构可以包含其他结构作为其组件;嵌套级别没有限制。

程序员可以定义结构的方法,这些方法可以在查询中使用与正常结构组件相同的语法。这样的方法除了指向它所属对象的指针(C++中的this指针)之外,不应该有任何参数,并且应该返回一个原子值(布尔值、数值、字符串或引用类型)。此外,该方法不应更改对象实例(不可变方法)。如果该方法返回一个字符串,则应该使用new char数组空间 来分配该字符串,因为临时变量将在复制其值后被删除。

因此,用户定义的方法可以用于创建虚拟组件——这些组件不存储在数据库中,而是使用其他组件的值进行计算。例如,FastDB dbDateTime类型仅包含整数时间戳组件和dbDateTime::year()、dbDateTime::month()等方法。。。因此,可以在应用程序中指定诸如“deliveryy.year=1999”之类的查询,其中交付记录字段具有dbDateTime类型。方法是在定义它们的应用程序上下文中执行的,其他应用程序和交互式SQL不可用。

3、数组

FastDB接受具有动态长度的数组作为记录的组成部分。不支持多维数组,但可以定义数组的数组。可以按数组字段的长度对结果集中的记录进行排序。FastDB提供了一组用于处理数组的特殊构造:

通过length()函数可以获得数组中元素的数量。

数组元素可以由[]运算符提取。如果索引表达式超出数组范围,将引发异常。

中的运算符可用于检查数组是否包含由左操作数指定的值。此操作只能用于原子类型的数组:具有布尔值、数值、引用或字符串组件。

数组可以使用update方法更新,该方法创建数组的副本并返回非常量引用。

数组元素的迭代由exists运算符执行。在exists关键字之后指定的变量可以用作exists量化器前面的表达式中数组的索引。此索引变量将遍历所有可能的数组索引值,直到表达式的值变为true或索引超出范围。条件

  exists i: (contract[i].company.location = 'US')

将选择位于“美国”的公司发货的所有详细信息,而查询

 not exists i: (contract[i].company.location = 'US')

将选择从“美国”以外的公司发货的所有详细信息。

允许嵌套的exists子句。使用嵌套的exists量化器相当于使用对应索引变量的嵌套循环。例如查询

    exists i: (contract[i].company.location = 'US')

将选择所有记录,在矩阵字段的元素中包含0,该字段的类型为array或array of integer。此构造等效于以下两个嵌套循环:

 bool result = false;
       for (int column = 0; column < matrix.length(); column++) { 
            for (int row = 0; row < matrix[column].length(); row++) { 
             if (matrix[column][row] == 0) { 
                     result = true;
             break;
                 }
            }
       }

使用索引的顺序至关重要!以下查询执行的结果

  exists row: (exists column: (matrix[column][row] = 0))

将与上一次查询的结果完全不同。在最后一种情况下,在空矩阵的情况下,程序只是由于无限循环而挂起。

4、字符串

FastDB中的所有字符串都有不同的长度,程序员不应该担心字符字段的最大长度的指定。数组可接受的所有操作也适用于字符串。除了它们之外,字符串还有一组自己的操作。首先,可以使用标准关系运算符将字符串相互比较。目前,FastDB只支持ASCII字符集(对应于C中的char类型)和忽略位置设置的逐字节字符串比较。

类似的运算符可用于将字符串与包含特殊通配符“%”和“_”的模式进行匹配。字符“_”与任何单个字符匹配,而字符“%”与零个或多个字符匹配。如果模式中的字符“%”和“_”前面有一个特殊的转义符(在转义关键字之后指定),则可以使用类似运算符的扩展形式和转义关键字将它们作为普通字符处理。

如果您使用USE_REGEX宏重建GigaBASE,那么您可以使用实现标准正则表达式的匹配运算符(基于GNU正则表达式库)。此运算符的第二个操作数指定了要匹配的正则表达式,并且应该是字符串文字。

可以通过in运算符搜索字符串中的子字符串。对于颜色字段包含“蓝色”的所有记录,表达式(颜色为“蓝色”)都将为true。如果搜索字符串的长度大于某个阈值(当前为512),则使用Boyer-Moore子字符串搜索算法,而不是直接的搜索实现。

字符串可以通过+或||运算符连接。最后一个是为了与ANSI SQL标准兼容而添加的。由于FastDB不支持在表达式中隐式转换为字符串类型,因此可以为字符串重新定义运算符+的语义。

Fastdb是一个面向对象的数据库系统,其主要目标是提供高效的、易于使用的数据存储和检索机制。本文将详细介绍Fastdb的特点和使用方法,并解释所有相关的接口。

一、特点

1. 高效性:Fastdb使用预分配对象的方式,减少了向磁盘分配空间的时间开销。它还使用了内存映射I/O技术,有效地减少了基于文件的I/O操作。

2. 安全性:Fastdb使用了事务机制,可以保证对数据的完整性。而且,它提供了可选的数据加密机制,以保护敏感数据。

3. 易于使用:Fastdb提供了面向对象的API,使得程序员可以快速、直接地存储和检索对象。同时,Fastdb提供了具有强大查询能力的索引机制,以便更高效地定位数据。

4. 可扩展性:Fastdb支持多种语言的接口,包括C++、Java、Python等,可以方便地与其他软件集成。

5. 易于部署:Fastdb是一个轻量级的数据库系统,可以很容易地安装和配置。

二、安装

Fastdb针对不同的操作系统提供了不同的安装包,可在其官方网站上下载。安装过程可以根据安装向导进行,也可以使用命令行方式安装。

三、使用

1. 创建数据库

在使用Fastdb之前,我们需要先创建一个数据库。可以通过以下代码创建并打开一个名为“MyDB”、大小为100MB的数据库:

```
  //创建数据库
  db_open("MyDB", 100000000);
  //获取根对象
  dbDatabase* db = dbDatabase::instance();
```

2. 定义对象

Fastdb的对象被定义为类,需要继承于dbObject类。例如,下面定义了一个Person类:

```
  class Person : public dbObject
  {
  public:
      char* name;
      int age;
      dbReference<Person> father;
      dbReference<Person> mother;
      dbArray<dbReference<Person> > children;
  };
```

在这个类中,我们定义了Person的姓名、年龄、父亲、母亲和孩子。dbReference表示一个对象引用,dbArray表示一个对象数组。dbObject类提供了一些常用的函数,例如dbObject::dbObject()、dbObject::~dbObject()、dbObject::clear()等。

3. 存储对象

我们可以使用dbDatabase::addObject()函数将一个新对象添加到数据库中,并返回一个dbReference对象。

```
  //创建一个新的Person对象并存储到数据库中
  Person* p = new Person;
  p->name = "Lucy";
  p->age = 25;
  dbReference<Person> ref = db->addObject(p);
```

4. 查询对象

Fastdb支持多种条件查询方式,可以快速地查找到我们需要的对象。例如,我们可以使用以下代码查找年龄为25岁的人:

```
  //查询年龄为25的人
  dbQuery q;
  q = db->createQuery();
  q.constrain(Person::age, opEqual, 25);
  q.execute();
  while (q.next()) {
      Person* p = q.object();
      cout << p->name << endl;
  }
```

其中,opEqual表示相等条件,还支持opLess、opGreater等。使用dbQuery::execute()函数执行查询,dbQuery::next()函数将游标移到下一个符合要求的对象位置,dbQuery::object()函数返回当前对象的指针。

5. 更新对象

我们可以使用dbDatabase::updateObject()函数更新已经存在的对象。例如,我们可以修改25岁的Lucy的名字:

```
  //修改Lucy的名字
  q = db->createQuery();
  q.constrain(Person::name, opEqual, "Lucy");
  q.constrain(Person::age, opEqual, 25);
  q.execute();
  while (q.next()) {
      Person* p = q.object();
      p->name = "Lucy Li";
      db->updateObject(p);
  }
```

6. 删除对象

我们可以使用dbDatabase::deleteObject()函数删除已经存在的对象。例如,我们可以删除所有年龄大于30岁的人:

```
  //删除年龄大于30的人
  q = db->createQuery();
  q.constrain(Person::age, opGreater, 30);
  q.execute();
  while (q.next()) {
      Person* p = q.object();
      db->deleteObject(p);
  }
```

四、接口解释

dbDatabase类

1. dbDatabase()

函数说明:构造函数,创建一个数据库对象。

2. static dbDatabase* instance()

函数说明:获取数据库的全局实例。

3. void open(const char* name, int size)

参数说明:name-数据库名称,size-数据库大小(字节)。

函数说明:打开一个数据库文件,并将它设置为当前数据库。

4. void close()

函数说明:关闭数据库文件。

5. dbReference<T> addObject(T* obj)

参数说明:obj-要添加的对象。

函数说明:将一个新对象添加到数据库末尾,并返回一个引用。

6. void updateObject(T* obj)

参数说明:obj-要更新的对象。

函数说明:将一个已经存在的对象更新到数据库中。

7. void deleteObject(T* obj)

参数说明:obj-要删除的对象。

函数说明:从数据库中删除一个已经存在的对象。

8. int commit()

函数说明:提交所有的事务。

9. void rollback()

函数说明:回滚所有的事务。

10. dbQuery createQuery()

函数说明:创建一个查询对象。

11. template <class T> dbReference<T> getReference(T* obj)

参数说明:obj-对象。

函数说明:获取一个对象的引用。

dbQuery类

1. dbQuery(dbDatabase* db)

参数说明:db-数据库对象。

函数说明:构造函数。

2. ~dbQuery()

函数说明:析构函数。

3. void close()

函数说明:关闭查询对象。

4. void reset()

函数说明:重置查询条件。

5. void constrain(dbFieldDescriptor* fd, dbComparisonOperator op, const void* value)

参数说明:fd-一个字段描述器,op-比较操作符,value-比较值。

函数说明:增加一个查询条件。

6. void orderBy(dbFieldDescriptor* fd, bool ascending=true)

参数说明:fd-一个字段描述器,ascending-是否升序排列。

函数说明:指定排序方式。

7. void select(const char* fieldName)

参数说明:fieldName-要返回的字段名称。

函数说明:指定要返回的字段。

8. bool execute()

函数说明:执行查询。

9. bool next()

函数说明:移动游标到下一个结果。

10. dbReference<T> object()

函数说明:返回当前游标所指向的对象引用。

dbFieldDescriptor类

1. dbFieldDescriptor(const char* name, int type, size_t length, int flags)

参数说明:name-字段名称,type-字段类型(int、float、double、char[]等),length-字段长度(对于char[]类型的字段有用),flags-字段属性(比如索引)。

函数说明:构造函数。

dbReference类

1. bool operator== (const dbReference& r)

参数说明:r-一个引用。

函数说明:判断两个引用是否相等。

2. bool operator!= (const dbReference& r)

参数说明:r-一个引用。

函数说明:判断两个引用是否不相等。

3. operator const T* ()

函数说明:将引用转换为指向T类型的指针。

dbArray类

1. dbArray<T>()

函数说明:构造函数。

2. void resize(int n, bool save=true)

参数说明:n-新数组大小,save-是否保留旧数据。

函数说明:重新调整数组大小。

3. void clear()

函数说明:清空数组内容。

4. void add(const T& item)

参数说明:item-要添加的项。

函数说明:将一个项添加到数组末尾。

5. T& operator[](int i) const

参数说明:i-数组下标。

函数说明:获取指定下标的项。

6. int length()

函数说明:获取数组长度。

以上就是Fastdb的详细介绍和所有接口的解释,希望对大家有用。

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

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

相关文章

《vtk9 book》 官方web版 第3章 - 计算机图形基础 (3 / 6)

3.8 演员几何 我们已经看到了光照属性如何控制演员的外观&#xff0c;以及相机如何结合变换矩阵将演员投影到图像平面上。剩下的是定义演员的几何形状&#xff0c;以及如何将其定位在世界坐标系中。 建模 计算机图形学研究中的一个重要主题是建模或表示物体的几何形状。…

一劳永逸的方法解决:LNK1168无法打开 xxx.exe 进行写入 报错问题

这种错误的产生原因&#xff1a; 运行程序退出不是按正常流退出&#xff0c;是按窗口右上角的 “X” 来关闭程序&#xff0c;但是后台的xxx.exe控制台程序还在运行&#xff1b;修改程序的代码后再运行&#xff0c;就会报LNK1168的错误&#xff1b; 报错示例&#xff1a; 解决方…

文本生成视频:从 Write-a-video到 Sora

2024年2月15日&#xff0c;OpenAI 推出了其最新的文本生成视频模型——Sora。Sora 能够根据用户的指令生成一分钟长度的高质量视频内容。这一创新的发布迅速在社会各界引发了广泛关注与深入讨论。本文将围绕本实验室发表于SIGGRAPH AISA 的 Write-a-video和 Sora 展开&#xff…

8核16G服务器多少钱?2024年腾讯云8核16G轻量服务器性能测评

腾讯云8核16G轻量服务器CPU性能如何&#xff1f;18M带宽支持多少人在线&#xff1f;轻量应用服务器具有100%CPU性能&#xff0c;18M带宽下载速度2304KB/秒&#xff0c;折合2.25M/s&#xff0c;系统盘为270GB SSD盘&#xff0c;月流量3500GB&#xff0c;折合每天116.6GB流量&…

真实案例分享:MOS管电源开关电路,遇到上电冲击电流超标

做硬件&#xff0c;堆经验。 分享一个案例&#xff1a;MOS管电源开关电路&#xff0c;遇到上电冲击电流超标&#xff0c;怎么解决的呢&#xff1f; 下面是正文部分。 —— 正文 —— 最近有一颗用了挺久的MOSFET发了停产通知&#xff0c;供应链部门找到我们研发部门&#xff0c…

Pycharm与Anaconda安装

网址&#xff1a; Pycharm&#xff1a;https://www.jetbrains.com/pycharm/ Anaconda&#xff1a;https://www.anaconda.com/download/ 官网下载速度太慢可以选择到清华源下载&#xff1a;https://repo.anaconda.com/archive/ 一&#xff1a;Anaconda安装 安装&#xff1a; …

Building Systems with the ChatGPT API

Building Systems with the ChatGPT API 本文是 https://www.deeplearning.ai/short-courses/building-systems-with-chatgpt/ 这门课程的学习笔记。 文章目录 Building Systems with the ChatGPT APIWhat you’ll learn in this course Language Models, the Chat Format and…

【C++ vector 类】

1. 标准库中的vector类 vector 类 的介绍&#xff1a; 注意&#xff1a; 1. vector是表示可变大小数组的序列容器。 2. 就像数组一样&#xff0c;vector 也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是…

长度为n的数组a初始值全为0,目标是把数组a变为数组b(1<=bi<=n), 可以进行任意次操作:选择长度为k的数组c,(1<=ci<=n且两两不同)

对于1<i<k, 把 a[c[i]] 改为c[i % k 1]。给定n&#xff0c;k和数组b&#xff0c;判断能否得到数组b。 题目 思路&#xff1a; #include <bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second #d…

消息服务--Kafka的简介和使用

消息服务--Kafka的简介和使用 前言异步解耦削峰缓存1、消息队列2、kafka工作原理3、springBoot KafKa整合3.1 添加插件3.2 kafKa的自动配置类3.21 配置kafka地址3.22 如果需要发送对象配置kafka值的序列化器3.3 测试发送消息3.31 在发送测试消息的时候由于是开发环境中会遇到的…

STM32按键控制LED蜂鸣器光敏联动

GPIO输入模式下的硬件和电路 以下为不同类型传感器电路图 硬件电路讲解 上面两种接线方式表示按键按下时是低电平&#xff0c;下面两种接线方式表示按键按下时引脚是高电平默认使用上面两种方式比较多。 C语言知识回顾 不同的数据类型 &#xff1a; char short int long longl…

Linux(Ubuntu)中安装vscode

①首先去vscode的官网下载.deb文件 网址&#xff1a;https://code.visualstudio.com/docs/?dvlinuxarm64_deb 注&#xff1a;如果linux端无法打开网页下载文件&#xff0c;可以在Windows端下载好用WinSCP传输到Linux。下载前注意下你的系统架构是arm还是amd&#xff0c;系统…

AHU 数据库 实验五

【实验名称】 实验5 数据库的数据更新与视图管理 【实验目的】 1. 熟悉数据更新操作的概念与操作类型&#xff1b; 2. 熟练掌握INSERT、UPDATE、DELETE语句的基本语法&#xff1b; 3. 熟练运用INSERT、UPDATE、DELETE语句实现数据的插入、修改与删除…

CentOS/Fedora/Ubuntu/Debian 系统 wget 命令

wget 是云服务器安装环境和面板常用下载命令。下载软件或从远程服务器下载备份到本地服务器&#xff0c;也可以使用 wget 把文件下载到云服务器上。 VPS wget 命令最常用使用方法如下&#xff1a; 安装 wget 一般来说 wget 命令是系统自带的&#xff0c;方面安装环境和面板&…

多维时序 | Matlab实现BiGRU-Mutilhead-Attention双向门控循环单元融合多头注意力机制多变量时序预测

多维时序 | Matlab实现BiGRU-Mutilhead-Attention双向门控循环单元融合多头注意力机制多变量时序预测 目录 多维时序 | Matlab实现BiGRU-Mutilhead-Attention双向门控循环单元融合多头注意力机制多变量时序预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.多维时序 …

族群争霸休闲养成小游戏

​游戏概述&#xff1a; 在一个由自然力量支配的幻想世界中&#xff0c;狼族与羊族的战争永无止境。 人族在两者之间寻求和平&#xff0c;建立起坚固的城墙&#xff0c;同时捕捉狼与羊来增强自身实力。 神族则在幕后观察&#xff0c;偶尔以神技介入战场&#xff0c;影响战局…

复盘-word

word-大学生网络创业交流会 设置段落&#xff0c;段后行距才有分 word-选中左边几行字进行操作 按住alt键进行选中 word复制excel随excel改变&#xff08;选择性粘贴&#xff09; 页边距为普通页边距定义 ##### word 在内容控件里面填文字&#xff08;调属性&#xff09…

JavaScript使用

文章目录 一、JavaScript简介二、JavaScript引入方式1、内部脚本2、外部脚本 三、JavaScript基础语法1、书写语法&输出语句2、变量&数据类型3、运算符4、流程控制语句&函数 四、JavaScript对象1、Array2、String3、自定义对象 五、BOM1、Window2、History3、Locati…

扩展CArray类,增加Contain函数

CArray不包含查找类的函数&#xff0c;使用不便。考虑扩展CArray类&#xff0c;增加Contain函数&#xff0c;通过回调函数暴露数组元素的比较方法&#xff0c;由外部定义。该方法相对重载数组元素的“”符号更加灵活&#xff0c;可以根据需要配置不同的回调函数进行比较 //类型…

C语言————字符函数与字符串函数

在编程的过程中&#xff0c;我们经常要处理字符和字符串&#xff0c;为了⽅便操作字符和字符串&#xff0c;C语⾔标准库中提供了⼀系列库函数&#xff0c;如追加&#xff0c;拷贝&#xff0c;替换等等接下来我们就学习⼀下这些函数&#xff0c;并且自实现。 gets 这个指令大家…