C++:STL简介和容器string用法篇

一、STL简介

       STL是C++中的标准模板库(Standard Template Library)的缩写。它是C++标准库的一部分,提供了一系列的数据结构和算法模板,包括各种容器、算法、迭代器、仿函数等,用于简化和加速C++程序的开发过程。STL的设计理念是提供通用、高效的数据结构和算法实现,使得开发者可以更加专注于业务逻辑的实现,提高代码的可读性、可维护性和可移植性。

       STL在C++中有以下几个主要用处:

  1. 提供丰富的数据结构:STL包含了各种常用的容器,如动态数组(vector)、双向链表(list)、映射(map)、集合(set)等。这些数据结构可以满足不同的需求,如存储数据、快速查找、有序存储等。

  2. 实现高效的算法:STL提供了大量的算法模板,包括排序、查找、变换、合并等,这些算法经过了优化和测试,通常具有高效的执行速度和可靠的性能。开发者可以直接使用这些算法,无需自己从头实现,提高了开发效率。

  3. 提供灵活的迭代器:STL中的迭代器提供了一种统一的访问数据结构元素的方式,包括输入迭代器、输出迭代器、正向迭代器、双向迭代器和随机访问迭代器等。开发者可以根据需要选择合适的迭代器类型进行数据遍历和操作。

  4. 支持泛型编程:STL是基于模板的,支持泛型编程。这意味着开发者可以编写通用的代码,适用于不同类型的数据结构和数据类型,提高了代码的复用性和通用性。

  5. 提高代码的可读性和可维护性:STL提供了经过优化和测试的标准化实现,使得代码更加清晰易懂。开发者可以直接使用STL提供的功能模块,避免了重复造轮子的工作,同时也降低了出错的风险,提高了代码的可维护性和可读性。

       综上所述,STL在提高开发效率和代码质量等方面具有很大的作用,是C++程序开发中不可或缺的重要工具。

       STL六大组件:

       网上有句话说:“不懂STL,不要说你会C++”。STL是C++中的优秀作品,有了它的陪伴,许多底层的数据结构以及算法都不需要自己重新造轮子,使我们能够快速地进行开发。

       我们的STL系列将从容器string部分开始介绍。

二、string类

       标准库类型string表示可变长的字符序列,使用string类型必须首先包含string头文件。作为标准库的一部分,string定义在命名空间std中。

1.定义和初始化string对象

       string是一个类,因此,实例化出string类时,会调用该类的构造函数。string对象也可以使用其他方式来初始化。常用的string对象构造方法有以下几种:

string s1;// 调用默认构造函数,s1是一个空字符串
string s2 = s1;// 调用拷贝构造函数
string s3 = "hello world!"; // 使用字符串初始化s3
string s4(10, 's'); // 使用10个's'字符初始化s4
string s5(s3, 6, 3);// 从第七个字符开始,将3个s3字符串中的字符拷贝到s5中
string s6(s3, 3);// 将前3个s3字符串中的字符拷贝到s6中

       在构造s5的过程中,可以不传第三个参数,那么编译器将会将第三个参数设为string::npos,而string::npos的值为大约42亿,也就是说,编译器会将s3中的从第七个字符开始,拷贝42亿个字符给s5,但是s3显然没有那么多字符。所以当遇到s3字符串的结尾时,编译器将会停止拷贝。那如果第三个参数传的过大,拷贝长度大于从开始到结尾的长度,那也是遇到字符串末尾然后停止拷贝。

       string类中重载了流插入<<、流提取>>操作符,使我们可以像打印、输入int型、char型等内置类型一样打印或输入string型。也重载了内置类型常用的大多数操作符。

2.遍历string对象

       string类中重载了'[]'运算符,使我们可以像遍历字符数组一样遍历string对象。

void test1()// string对象的遍历
{string s1("hello world!");for (int i = 0; i < s1.size(); i++){cout << s1[i] << ' ';}
}int main()
{test1();return 0;
}

       运行程序,结果如下:

       也可以将上面的循环换为范围for循环来遍历string对象,使用起来更加方便。

三、string类成员函数

1.容量

(1)size和length

size_t size() const;
size_t length() const;

       string类中有求字符串长度的函数size()和length(),它们的作用相同。调用方法如下:

void test1()
{string s1("hello world!");string s2("hellohello world!");cout << s1.size() <<endl;cout << s2.length();
}

       运行程序,结果如下:

(2)max_size

       string类中的max_size()函数用于求字符串的潜在最大长度。

size_t max_size() const;

       调用该函数之后,会得到一个非常大的数字。

(3)resize

void resize (size_t n);
void resize (size_t n, char c);

       string类中提供了两个调节字符串大小的函数。第一个参数都是一个无符号整形,意思是将字符串大小调整为n。若字符串长度大于n,那么n之后的字符将会丢弃,若字符串的长度小于n,那么第一个函数将会在n之后填充空字符,第二个函数则会使用指定的字符填充。

       我们知道,字符串末尾还隐藏了一个‘\0’字符。空字符是不计入长度的。计算字符串长度时,遇到任意空字符就停止计数。打印的时候也是以任意空字符为结尾的。

void test1()
{string s1("hello\0\0\0\0\0 world!    ");string s2("hellohello world!");//s1.resize(18);cout << s1 << 'a' << endl;cout << s1.size() << endl;}

       运行程序,结果如下:

       但是我们将resize函数取消注释,再次运行程序:

       发现长度来到了18,也就是说,编译器填充的空字符,是计入长度的。

       通过监视窗口我们看到,没有执行resize语句时,s1中字符串只有五个字符,执行之后,后面13个字符都是\0并且计入长度。

(4)capacity

size_t capacity() const;

       string类中有计算容量的成员函数,它表示编译器为对象实际分配的内存空间,它可以大于或等于字符串的长度。若容量满时,会自动扩容。

(5)reverse

void reserve (size_t n = 0);

       reverse函数使用来修改字符串容量的。给reverse传的参数n是告诉编译器假定字符串的长度为n,然后让编译器重新为对象分配空间。编译器会结合实际字符串长度来分配空间。若n小于实际字符串长度,容量的变化具体看编译器。

(6)clear

void clear();

       它的作用为清空字符串。使对象变为长度为0的字符串。

(7)empty

bool empty() const;

       它的作用是判断字符串是否为空,并不会改变字符串中的内容。

(8)shrink_to_fit

bool empty() const;

       请求字符串减小其容量以适应其大小。

2.元素访问

(1)operator[]

       string类中具有运算符重载, 使我们可以像访问数组那样访问string对象中的值。

char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;

(2)at

char& at (size_t pos);
const char& at (size_t pos) const;

       返回对字符串中位置pos处的字符的引用。

(3)back

char& back();
const char& back() const;

       返回对字符串最后一个字符的引用。此函数不应在空字符串上调用。

(4)front

char& front();
const char& front() const;

       返回对字符串第一个字符的引用。此函数不应在空字符串上调用。

3.修改

(1)operator+=

string& operator+= (const string& str);
string& operator+= (const char* s);
string& operator+= (char c);

       string具有+=重载函数,使我们可以像内置类型一样使用+=操作符:

void test1()
{string s1("hello world!");string s2("hi");s1 += "sss";s1 += 'a';s1 += s2;cout << s1 << endl;cout << s1.size() << endl;
}

       运行代码,结果如图所示:

       有了+=重载操作符重载,我们可以很方便地为字符串后添加字符。

(2)append

string& append (const string& str);
string& append (const string& str, size_t subpos, size_t sublen);
string& append (const char* s);
string& append (const char* s, size_t n);
string& append (size_t n, char c);
template <class InputIterator>
string& append (InputIterator first, InputIterator last);

       append也表示向字符串的末尾添加字符串。它重载了许多函数,实现了很多功能。

string& append (const string& str);

       表示向一个string对象末尾添加另一个string对象,也就是在一个字符串的末尾添加另一串字符串。

string& append (const string& str, size_t subpos, size_t sublen);

       表示向一个string对象末尾添加另一个string对象的一部分,它从subpos位置开始,直到拷贝长度达到sublen时为止或者直到遇到字符串末尾。

string& append (const char* s);

       表示向string对象末尾附加一个由指针变量指向的字符串。

string& append (const char* s, size_t n);

       表示向string对象末尾附加一个由指针变量指向的字符串的前n个字符。

string& append (size_t n, char c);

       表示向string对象末尾附加n个c字符。

(3)push_back

void push_back (char c);

       表示向string对象末尾附加1个c字符。

(4)assign

string& assign (const string& str);
string& assign (const string& str, size_t subpos, size_t sublen);
string& assign (const char* s);
string& assign (const char* s, size_t n);
string& assign (size_t n, char c);

        assign表示赋值,将当前值清空并赋新值。

string& assign (const string& str);

       表示将另一个string对象赋给当前string对象。

string& assign (const string& str, size_t subpos, size_t sublen);

       表示将另一个string对象的一部分赋给当前string对象。从subpos开始,到sublen处结束,或遇到字符串尾结束。

string& assign (const char* s);

       表示将s指向的字符串赋给当前string对象。

string& assign (const char* s, size_t n);

        表示将s指向的字符串的前n个字符赋给当前string对象。

string& assign (size_t n, char c);

       表示将n个c字符赋给当前string对象。

(5)insert

 string& insert (size_t pos, const string& str);string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);string& insert (size_t pos, const char* s);string& insert (size_t pos, const char* s, size_t n);string& insert (size_t pos, size_t n, char c);
void insert (iterator p, size_t n, char c);

        insert也表示插入,它支持在任意位置插入。不过它的效率不高。

string& insert (size_t pos, const string& str);

       表示在下标pos之后插入一个string对象。

string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);

       表示在下标pos之后插入一个string对象的一部分,它从subpos处开始,直到拷贝长度达到sublen或者遇到字符串结尾。

string& insert (size_t pos, const char* s);

       表示在pos位置插入一个s指向的字符串。

string& insert (size_t pos, const char* s, size_t n);

       表示在pos位置插入一个s指向的字符串的前n个字符。

string& insert (size_t pos, size_t n, char c);

        表示在pos位置插入n个字符c。

(6)erase

string& erase (size_t pos = 0, size_t len = npos);

       erase表示删除,删除从pos位置开始, 直到删除长度达到len或者对象中已经无字符。若不传参数,那么表示全部删除。

(7)replace

string& replace (size_t pos,  size_t len,  const string& str);
string& replace (size_t pos,  size_t len,  const string& str,size_t subpos, size_t sublen);
string& replace (size_t pos,  size_t len,  const char* s);
string& replace (size_t pos,  size_t len,  const char* s, size_t n);
string& replace (size_t pos,  size_t len,  size_t n, char c);

       replace表示替换。

string& replace (size_t pos,  size_t len,  const string& str);

       表示从下标pos位置开始,len长度的字符替换为另一个string对象中的字符串。

string& replace (size_t pos,  size_t len,  const string& str,size_t subpos, size_t sublen);

       表示从下标pos位置开始,len长度的字符替换为另一个string对象中的字符串的一部分,从小标subpos位置开始,拷贝sublen长度的字符串或遇到字符串末尾。

string& replace (size_t pos,  size_t len,  const char* s);

       表示从下标pos位置开始,len长度的字符替换为s指向的字符串。

string& replace (size_t pos,  size_t len,  const char* s, size_t n);

       表示从下标pos位置开始,len长度的字符替换为s指向的字符串的前n个字符。

string& replace (size_t pos,  size_t len,  size_t n, char c);

       表示从下标pos位置开始,len长度的字符替换为n个c字符。

(8)swap

void swap (string& str);
void swap (string& x, string& y);

       交换两string对象的值。

void test1()
{string s1("hello world!");string s2("abcdefg");s1.swap(s2);cout << s1 << endl;cout << s2 << endl;
}

       运行代码,结果如下图所示:

(9)pop_back

void pop_back();

       尾部删除一个字符。

(10)getline

istream& getline (istream& is, string& str, char delim);
istream& getline (istream& is, string& str);

       从流中提取一行字符串到string对象中,直到遇到delim(界定字符)或换行符。若指定了界定字符,那么当输入界定字符之后,编译器会只保留界定字符之前的字符,将string对象存储的值删除,并添加上新输入的字符。若没有指定界定字符,那么当遇到换行符时,即代表输入结束。

4.字符串操作

(1)c_str

const char* c_str() const;

       返回一个字符串指针,指向一块存储着C风格字符串的空间。字符串的末尾附加了一个空字符。

(2)data

const char* data() const;

       返回一个字符串指针,指向一块存储着C风格字符串的空间。在C++11之前,该字符串末尾不附加空字符,C++11之后,附加了一个空字符,执行与c_str一样的操作。

(3)copy

size_t copy (char* s, size_t len, size_t pos = 0) const;

       从pos位置开始,拷贝len个长度的字符到s指向的空间中。返回拷贝字符的个数。

(4)find

size_t find (const string& str, size_t pos = 0) const;
size_t find (const char* s, size_t pos = 0) const;
size_t find (const char* s, size_t pos, size_type n) const;
size_t find (char c, size_t pos = 0) const;

       第一个重载成员函数可以查找子字符串,pos是开始查找的位置。若找到则返回子字符串在字符串中的下标,若找不到则返回nops。

       第二个重载成员函数可以查找s指向的字符串。

       第三个重载成员函数可以查找s指向的字符串,第三个参数n是查找的长度,若小于被查找的字符串长度,则查找前n个字符组成的字符串。

       第四个重载成员函数可以查找指定的字符。

(5)rfind

size_t rfind (const string& str, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos, size_t n) const;
size_t rfind (char c, size_t pos = npos) const;

       查找要查找的对象最后一次出现的位置。

(6)find_first_of

size_t find_first_of (const string& str, size_t pos = 0) const;
size_t find_first_of (const char* s, size_t pos = 0) const;
size_t find_first_of (const char* s, size_t pos, size_t n) const;
size_t find_first_of (char c, size_t pos = 0) const;

       在string对象中查找一个字符,它同时出现在另一个对象中并且在string对象中是第一个这样的字符。返回该字符的下标。支持查找另一个string对象、指针指向的空间,单个字符。

size_t find_last_of (const string& str, size_t pos = npos) const;
size_t find_last_of (const char* s, size_t pos = npos) const;
size_t find_last_of (const char* s, size_t pos, size_t n) const;
size_t find_last_of (char c, size_t pos = npos) const;

       在string对象中查找一个字符,它同时出现在另一个对象中并且在string对象中是最后一个这样的字符。

(7)find_first_not_of

size_t find_first_not_of (const string& str, size_t pos = 0) const;
size_t find_first_not_of (const char* s, size_t pos = 0) const;
size_t find_first_not_of (const char* s, size_t pos, size_t n) const;
size_t find_first_not_of (char c, size_t pos = 0) const;

       在string对象中查找一个字符,它在另一个对象中不存在,并且是第一个这样的字符,返回该字符的下标。

(8)find_last_not_of

size_t find_last_not_of (const string& str, size_t pos = npos) const;
size_t find_last_not_of (const char* s, size_t pos = npos) const;
size_t find_last_not_of (const char* s, size_t pos, size_t n) const;
size_t find_last_not_of (char c, size_t pos = npos) const;

       在string对象中查找一个字符,它在另一个对象中不存在,并且是最后一个这样的字符,返回该字符的下标。

(9)substr

string substr (size_t pos = 0, size_t len = npos) const;

       创建一个子字符串,该子字符串的值为string对象中从pos位置开始,len个长度或到达字符串末尾的字符串的拷贝。

(10)compare

int compare (const string& str) const;
int compare (size_t pos, size_t len, const string& str) const;
int compare (size_t pos, size_t len, const string& str,size_t subpos, size_t sublen) const;
int compare (const char* s) const;
int compare (size_t pos, size_t len, const char* s) const;
int compare (size_t pos, size_t len, const char* s, size_t n) const;

       将字符串的值与参数指定的字符串的值进行比较。

       返回值:

  • =0,两字符串相等。
  • >0,string对象1>string对象2。若遇到第一个字符串与第二个字符串不相等的第一个字符,比较它们的ascii值。
  • <0,string对象1<string对象2。
int compare (size_t pos, size_t len, const string& str) const;

       将string对象中从pos位置开始,len个长度的字符串与另一个对象比较。

int compare (size_t pos, size_t len, const string& str,size_t subpos, size_t sublen) const;

       将string对象中从pos位置开始,len个长度的字符串与另一个对象中的subpos位置开始,sublen长度的字符串比较。

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

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

相关文章

shell脚本开发基础

shell脚本开发基础 什么是linux内置命令&#xff1f;什么是外置命令 内置命令&#xff1a;在系统启动时就加载入内存&#xff0c;常驻内存&#xff0c;执行效率更高&#xff0c;但是占用资源&#xff0c;cd 外置命令&#xff1a;系统需要从硬盘中读取程序文件&#xff0c;再读…

第八篇【传奇开心果系列】Python微项目技术点案例示例:以微项目开发为案例,深度解读Dearpygui 编写图形化界面桌面程序的优势

传奇开心果博文系列 系列博文目录Python微项目技术点案例示例系列 博文目录前言一、开发图形化界面桌面程序的优势介绍二、跨平台特性示例代码和解析三、高性能特性示例代码和解析四、简单易用特性示例代码和解析五、扩展性强示例代码和解析六、现代化设计示例代码和解析七、知…

什么是云渗透测试?

推荐阅读&#xff1a; 什么是安全态势&#xff1f; 什么是人肉搜索 什么是恶意软件&#xff1f; 什么是数字取证&#xff1f; 什么是语音网络钓鱼&#xff1f; 什么是网络安全中的社会工程&#xff1f; 什么是网络安全中的威胁情报&#xff1f; 什么是端点检测和响应 (…

linux 阿里云服务器安装ImageMagick和php扩展imagick

操作系统版本 Alibaba Cloud Linux 3.2104 LTS 64位 # 1.安装ImageMagick yum install -y ImageMagick ImageMagick-devel # 没有pecl要先安装pecl 和头文件 sudo yum install php-devel # 2.pecl 安装扩展 pecl install imagick #寻找所有php.ini文件 find / -name php.…

静态随机存储器(SRAM)

目录 介绍 基本的 SRAM 存储单元阵列 1. SRAM 存储单元 2. SRAM 阵列 3. SRAM 阵列的读写操作 4. SRAM 阵列的扩展 5. SRAM 阵列的应用 6. SRAM 阵列的优缺点 基本的 SRAM 逻辑结构 1. 存储单元 2. 存储单元阵列 3. 译码器 4. 读写电路 5. 控制逻辑 6. SRAM 逻辑…

【前端之ES6语法】

前端之ES6语法 1. ES6简介2. ES6新特性3.ES6不支持&#xff0c;使用babel3.1 参考文献 4.let和const命令5. 模版字符串6.函数之默认值、剩余参数7. 函数之扩展运算符、箭头函数8.箭头函数this指向和注意事项9.解构赋值10.对象扩展11.Symbol类型12.Set集合类型13.Map数据类型14.…

React自定义Componment和State深层次理解-07

本节主要从底层原理上分析下React开发相关的内容和注意事项&#xff0c;本节会围绕使用展开&#xff0c;而非源码讲解。 Componment详解 什么是组件 在 MVVM架构出现之前&#xff0c;组件主要分为两种。 狭义上的组件&#xff0c;又称为 UI 组件&#xff0c;比如 Tabs 组件、…

Java计算日期相差天数的几种方法

Java计算日期相差天数的几种方法 &#x1f5d3;️ Java计算日期相差天数的几种方法摘要引言一、使用java.util.Date和java.util.Calendar&#x1f4c5;1. 使用java.util.Date示例代码 2. 使用java.util.Calendar示例代码 二、使用java.time.LocalDate&#x1f4c6;示例代码 三、…

微信小程序文本框输入显示已经输入的字数

我们遇到这样的需求&#xff0c;就是微信小程序的输入框下面需要显示输入的字数&#xff1a; 我们通常会使用bindinput事件&#xff0c;让显示的字数等于value的长度&#xff0c;看下面的图&#xff1a; 但在实践中&#xff0c;真机测试中&#xff0c;我们会发现以下问题: 这个…

IP编址、进制转换、IP地址分类、变长子网掩码VLSM、无类域间路由CIDR

前言 网络层位于数据链路层与传输层之间。网络层中包含了许多协议&#xff0c;其中最为重要的协议就是IP协议。网络层提供了IP路由功能。理解IP路由除了要熟悉IP协议的工作机制之外&#xff0c;还必须理解IP编址以及如何合理地使用IP地址来设计网络。 IP编址 每个网段上都有两…

Java的类路径究竟是什么?

回答 问了chatgpt这个问题&#xff0c;首先类路径的定义是&#xff1a; 是指一组路径&#xff0c;这些路径告诉Java虚拟机&#xff08;JVM&#xff09;和类加载器在哪里可以找到应用程序所需的类和资源文件。说白了就是在运行java程序的时候需要先将java源代码编译成class文件…

基础IO用户缓冲区 、inode、硬软链接【Linux】

文章目录 用户缓冲区磁盘磁盘分区EXT2文件系统的存储方案 inode软链接硬链接 用户缓冲区 代码一&#xff1a; 1 #include<stdio.h>2 #include<unistd.h>3 #include<string.h> 4 int main()5 {6 const char * fstr &…

基于FIDO2和USBKEY硬件的SSH认证

在 8.2&#xff08;最新为 8.3&#xff09;版本中&#xff0c;OpenSSH 提供了对 FIDO 和 UAF 的支持。从此用户就可以用硬件 USBKEY 证书进行 SSH 原生认证。这样可以实现简捷、有效和安全的 SSH 认证。本文我们就就少一下 FIDO2 以及 OpenSSH 对其的支持&#xff0c;并尝试一下…

【调试笔记-20240521-Linux-编译 QEMU/x86_64 可运行的 OpenWrt 固件】

调试笔记-系列文章目录 调试笔记-20240521-Linux-编译 QEMU/x86_64 可运行的 OpenWrt 固件 文章目录 调试笔记-系列文章目录调试笔记-20240521-Linux-编译 QEMU/x86_64 可运行的 OpenWrt 固件 前言一、调试环境操作系统&#xff1a;Ubuntu 22.04.4 LTS编译环境调试目标 二、调…

日志的介绍及简单实现

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 日志是什么&#xff1f; 为什么需要日志&#xff1f; 实现一个简单日志 时间戳 clock_gettime time & localtime 可变模板参数(使用C语言)&#xff0c;va_start & va_end & vsprintf 宏 __LINE__…

Digital Image Processing System(DIPS)

数字图像处理系统 Digital Image Processing System&#xff08;DIPS&#xff09; 早前版本&#xff1a; ​​​​​​​DIPS_YTPC OCR-CSDN博客

数据结构和算法|排序算法系列(二)|冒泡排序

首先需要你对排序算法的评价维度和一个理想排序算法应该是什么样的有一个基本的认知&#xff1a; 《Hello算法之排序算法》 主要内容来自&#xff1a;Hello算法11.3 冒泡排序 我觉得冒泡排序非常有意思&#xff0c;也非常简单&#xff0c;就是不停地交换相邻的元素即可&#…

ElasticSearch插件版本与ES版本不对应的解决方案

一、背景 最近需要给es安装ik、hanlp分词器和ingest-attachment管道&#xff0c;服务器已有的es版本为8.5.3&#xff08;似乎太新了&#xff09;&#xff0c;hanlp和ingest-attachment都没有这么高的版本&#xff0c;因此只能下载相对老的版本&#xff0c;然后自己修改配置文件…

安全设计 | 安全设计不得马虎!微软STRIDE威胁建模方法让你事半功倍,快速发现应用安全隐患!

STRIDE威胁建模方法最早发表于2006年11月的《MSDN杂志》&#xff0c;作者是微软的工程师Shawn Hernan、Scott Lambert 、Tomasz Ostwald 和 Adam Shostack。那我们为什么要进行威胁建模&#xff1f; 如何使用数据流图对系统进行威胁建模&#xff1f;如何减轻威胁&#xff1f;接…

java项目之桂林旅游景点导游平台源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的桂林旅游景点导游平台。 项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 桂林旅游景点导游…