【C++初阶】C++STL详解(一)—— string类(上)

简介: 【C++初阶】C++STL详解(一)—— string类(上)

C++STL详解(一)—— sring类

1. string的定义方式

string类实现了多个构造函数的重载,常用的构造函数如下:

string();  //构造一个空字符串
string(const char* s);  //复制s所指的字符序列
string(const char* s, size_t n);  //复制s所指字符序列的前n个字符
string(size_t n, char c);  //生成n个c字符的字符串
string(const string& str);  //生成str的复制品
string(const string& str, size_t pos, size_t len = npos);  //复制str中从字符位置pos开始并跨越len个字符的部分

使用示例:

string s1;                     //构造空字符串
string s2("hello string");     //复制"hello string"
string s3("hello string", 3);  //复制"hello string"的前3个字符
string s4(10, 's');            //生成10个's'字符的字符串
string s5(s2);                 //生成s2的复制品
string s6(s2, 0, 4);           //复制s2中从字符位置0开始并跨越4个字符的部分

2. string的插入

1、使用push_back进行尾插–插入单个字符

append–插入字符串

void push_back (char c);
#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s;
  s.push_back('C');
  s.push_back('S');
  s.push_back('D');
  s.push_back('N');
  cout << s << endl; //CSDN
  s.append("hello");
  cout << s << endl; //CSDNhello
  return 0;
}

2、使用insert插入


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

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

iterator insert (iterator p, char c);


#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("C"); //C
  //insert(pos, str)在pos位置插入字符串str
  s.insert(1, "S"); //CS
  //insert(pos, string)在pos位置插入string对象
  string t("D");
  s.insert(2, t); //CSD
  //insert(pos, char)在pos位置插入字符char
  s.insert(s.end(), 'N'); //CSDN
  cout << s << endl; //CSDN
  return 0;
}

3.string的拼接

使用append函数完成string的拼接:

string& append (const string& str);
string& append (const char* s);
string& append (size_t n, char c);
#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s1("I");
  string s2(" like");
  //append(string)完成两个string对象的拼接
  s1.append(s2); //I like
  //append(str)完成string对象和字符串str的拼接
  s1.append(" C++"); //I like C++
  //append(n, char)将n个字符char拼接到string对象后面
  s1.append(3, '!'); //I like C++!!!
  cout << s1 << endl; //I like C++!!!
  return 0;
}

4.string的删除

1、使用pop_back进行尾删

void pop_back();
#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("C++");
  s.pop_back();
  s.pop_back();
  cout << s << endl; //C
  return 0;
}

2、使用erase删除

string& erase (size_t pos = 0, size_t len = npos);
iterator erase (iterator p);
iterator erase (iterator first, iterator last);
#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("I like C++");
  //erase(pos, n)删除pos位置开始的n个字符
  s.erase(8, 5); //I like C
  //erase(pos)删除pos位置的字符
  s.erase(s.end()-1); //I like
  //erase(pos1, pos2)删除[pos1pos2)上所有字符
  s.erase(s.begin() + 1, s.end()); //I
  cout << s << endl; //I
  return 0;
}

5.string的查找

1、使用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 (char c, size_t pos = 0) const;

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s1("http://www.cplusplus.com/reference/string/string/find/");
  //find(string)正向搜索与string对象所匹配的第一个位置
  string s2("www");
  size_t pos1 = s1.find(s2);
  cout << pos1 << endl; //7
  //find(str)正向搜索与字符串str所匹配的第一个位置
  char str[] = "cplusplus.com";
  size_t pos2 = s1.find(str);
  cout << pos2 << endl;  //11
  //find(char)正向搜索与字符char所匹配的第一个位置
  size_t pos3 = s1.find(':');
  cout << pos3 << endl; //4
  return 0;
}

2、使用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 (char c, size_t pos = npos) const;

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s1("http://www.cplusplus.com/reference/string/string/find/");
  //rfind(string)反向搜索与string对象所匹配的第一个位置
  string s2("string");
  size_t pos1 = s1.rfind(s2);
  cout << pos1 << endl; //42
  //rfind(str)反向搜索与字符串str所匹配的第一个位置
  char str[] = "reference";
  size_t pos2 = s1.rfind(str);
  cout << pos2 << endl;  //25
  //rfind(char)反向搜索与字符char所匹配的第一个位置
  size_t pos3 = s1.rfind('/');
  cout << pos3 << endl; //53
  return 0;
}

90b3b0d632c54709b73c17544e21b694.png

212497c811cf48918ee1ffc901ed9dfc.png3、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;

正向查找在原字符串中第一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置。若查找失败,则返回npos。(npos定义为保证大于任何有效下标的值。)

#include<iostream>
using namespace std;
int main()
{
    string str="abcdefab";
    cout<<str.find_first_of('a')<<endl;//第二个参数为0,默认从下标为0开始查找。
    cout<<str.find_first_of("hce")<<endl;//待查串hce第一个出现在原串str中的字符是c,返回str中c的下标2,故结果为2。
    cout<<str.find_first_of("ab",1)<<endl;//从下标为1开始查,待查串ab第一个出现在原串str中的字符是b,返回b的下标,结果为1。
    cout<<str.find_first_of('h')<<endl;//原串没有待查字符h,故查不到,返回npos。
    cout<<str.find_first_of("hw")<<endl;//待查子串任一字符在原串中都找不到,故查不到,返回npos。
    return 0;
}
//有效的下标应该在0~len-1范围内。len=str.size();

4、find_last_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;


逆向查找在原字符串中最后一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置。若查找失败,则返回npos。(npos定义为保证大于任何有效下标的值。)

#include<iostream>
using namespace std;
int main()
{
    string str="abcdefab";
    cout<<str.find_last_of("wab")<<endl;//原串最后一个字符首先与待查子串的每一个字符一一比较,一旦有相同的就输出原串该字符的下标.。结果为b的下标7。
    cout<<str.find_last_of("wab",5)<<endl;
    //从原串中下标为5开始逆向查找,首先f与待查子串每一字符比较,若有相同的就输出该字符在原串的下标。
    //若一个都没有,就依次逆向比较,即e再与待查子串一一比较,直到原串的b与待查子串中的b相同,然后输出该b在原串的下标1。
    cout<<str.find_last_of("fab",5)<<endl;//输出f在原串的下标5。
    cout<<str.find_last_of("fab",7)<<endl;//输出b在原串的下标7。
    cout<<str.find_last_of("hwk")<<endl;//原串没有待查子串的任何字符,故返回npos。
    return 0;
}
//有效的下标应该在0~len-1范围内。len=str.size();

6.string的比较

使用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;


比较规则:

 1、比较字符串中第一个不匹配的字符值较小,或者所有比较字符都匹配,但比较字符串较短,则返回小于0的值。

 2、比较字符串中第一个不匹配的字符值较大,或者所有比较字符都匹配,但比较字符串较长,则返回大于0的值。

 3、比较的两个字符串相等,则返回0。

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s1("hello world");
  string s2("hello CSDN");
  //"hello world"和"hello CSDN"比较
  cout << s1.compare(s2) << endl; //1
  //"ell"和"hello CSDN"比较
  cout << s1.compare(1, 3, s2) << endl; //-1
  //"hello"和"hello"比较
  cout << s1.compare(0, 4, s2, 0, 4) << endl; //0
  return 0;
}

注意:除了支持string类之间进行比较,compare函数还支持string类和字符串进行比较。

7.string的替换

使用replace函数完成string的替换:

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

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

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("hello world");
  //replace(pos, len, str)将pos位置开始的len个字符替换为字符串str
  s.replace(6, 4, "CSDN"); //hello CSDNd
  //replace(pos, len, n, char)将pos位置开始的len个字符替换为n个字符char
  s.replace(10, 1, 3, '!'); //hello CSDN!!!
  cout << s << endl;
  return 0;
}
#include <iostream>

但一般不使用repalce,因为要挪动数据,时间复杂度较高,而是通过空间换时间,比如下面这道题:990f5fa1e44942b19fd9cbd191f26268.png

8.string的交换

使用swap函数完成两个string类的交换:

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

void swap (string& str);

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s1("hello");
  string s2("CSDN");
  //使用string类的成员函数swap交换s1和s2
  s1.swap(s2);
  cout << s1 << endl; //CSDN
  cout << s2 << endl; //hello
  //使用非成员函数swap交换s1和s2
  swap(s1, s2);
  cout << s1 << endl; //hello
  cout << s2 << endl; //CSDN
  return 0;
}

9.string的大小和容量

1、使用size函数或length函数获取当前有效字符的个数

size_t size() const;

size_t length() const;

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("CSDN");
  cout << s.size() << endl; //4
  cout << s.length() << endl; //4
  return 0;
}

2、使用max_size函数获取string对象对多可包含的字符数

size_t max_size() const;

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("CSDN");
  cout << s.max_size() << endl; //4294967294
  return 0;
}

3、使用capacity函数获取当前对象所分配的存储空间的大小

size_t capacity() const;

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("CSDN");
  cout << s.capacity() << endl; //15
  return 0;
}

4、使用resize改变当前对象的有效字符的个数


void resize (size_t n);

void resize (size_t n, char c);


resize规则:

 1、当n大于对象当前的size时,将size扩大到n,扩大的字符为c,若c未给出,则默认为’\0’。

 2、当n小于对象当前的size时,将size缩小到n。

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s1("CSDN");
  //resize(n)n大于对象当前的size时,将size扩大到n,扩大的字符默认为'\0'
  s1.resize(20);
  cout << s1 << endl; //CSDN
  cout << s1.size() << endl; //20
  cout << s1.capacity() << endl; //31
  string s2("CSDN");
  //resize(n, char)n大于对象当前的size时,将size扩大到n,扩大的字符为char
  s2.resize(20, 'x');
  cout << s2 << endl; //CSDNxxxxxxxxxxxxxxxx
  cout << s2.size() << endl; //20
  cout << s2.capacity() << endl; //31
  string s3("CSDN");
  //resize(n)n小于对象当前的size时,将size缩小到n
  s3.resize(2);
  cout << s3 << endl; //CS
  cout << s3.size() << endl; //2
  cout << s3.capacity() << endl; //15
  return 0;
}

注意:若给出的n大于对象当前的capacity,则capacity也会根据自己的增长规则进行扩大->进行开空间+初始化

5、使用reserve改变当前对象的容量大小

void reserve (size_t n = 0);

reserve规则:

 1、当n大于对象当前的capacity时,将capacity扩大到n或大于n。

 2、当n小于对象当前的capacity时,什么也不做。


 注意:如果使用clear()清理了数据,会缩容,反之不会缩容;但不建议缩容,否则时间换空间(开辟小空间、拷贝、释放之前的大空间)->不值得

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("CSDN");
  cout << s << endl; //CSDN
  cout << s.size() << endl; //4
  cout << s.capacity() << endl; //15
  //reverse(n)当n大于对象当前的capacity时,将当前对象的capacity扩大为n或大于n
  s.reserve(20); 
  cout << s << endl; //CDSN
  cout << s.size() << endl; //4
  cout << s.capacity() << endl; //31
  //reverse(n)当n小于对象当前的capacity时,什么也不做
  s.reserve(2);
  cout << s << endl; //CDSN
  cout << s.size() << endl; //4
  cout << s.capacity() << endl; //31
  return 0;
}

注意:此函数对字符串的size没有影响,并且无法更改其内容。只进行开空间->减少消耗,提高效率

6、使用clear删除对象的内容,删除后对象变为空字符串

void clear();

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("CSDN");
  //clear()删除对象的内容,该对象将变为空字符串
  s.clear();
  cout << s << endl; //空字符串
  return 0;
}

7、使用empty判断对象是否为空

bool empty() const;

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("CSDN");
  cout << s.empty() << endl; //0
  //clear()删除对象的内容,该对象将变为空字符串
  s.clear();
  cout << s.empty() << endl; //1
  return 0;
}

10.string中元素的访问

1、[ ]+下标

 因为string类对[ ]运算符进行了重载,所以我们可以直接使用[ ]+下标访问对象中的元素。并且该重载使用的是引用返回,所以我们可以通过[ ]+下标修改对应位置的元素。

char& operator[] (size_t pos);

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

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("CSDN");
  //[]+下标访问对象元素
  for (size_t i = 0; i < s.size(); i++)
  {
    cout << s[i];
  }
  cout << endl;
  //[]+下标修改对象元素内容
  for (size_t i = 0; i < s.size(); i++)
  {
    s[i] = 'x';
  }
  cout << s << endl; //xxxx
  return 0;
}

a12957728e244d5bab26ba029d1f94a4.png

2、使用at访问对象中的元素

 因为at函数也是使用的引用返回,所以我们也可以通过at函数修改对应位置的元素。

char& at (size_t pos);

const char& at (size_t pos) const;

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("CSDN");
  for (size_t i = 0; i < s.size(); i++)
  {
    //at(pos)访问pos位置的元素
    cout << s.at(i);
  }
  cout << endl;
  for (size_t i = 0; i < s.size(); i++)
  {
    //at(pos)访问pos位置的元素,并对其进行修改
    s.at(i) = 'x';
  }
  cout << s << endl; //xxxx
  return 0;
}

62967fe8209a4ad99cdc9f51cee58738.png3、使用范围for访问对象中的元素

 需要特别注意的是:若是需要通过范围for修改对象的元素,则用于接收元素的变量e的类型必须是引用类型,否则e只是对象元素的拷贝,对e的修改不会影响到对象的元素。

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("CSDN");
  //使用范围for访问对象元素
  for (auto e : s)
  {
    cout << e;
  }
  cout << endl; //CSDN
  //使用范围for访问对象元素,并对其进行修改
  for (auto& e : s) //需要修改对象的元素,e必须是引用类型
  {
    e = 'x';
  }
  cout << s << endl; //xxxx
  return 0;
}

其实,范围for的底层就是迭代器

4、使用迭代器访问对象中的元素

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string s("CSDN");
  //使用迭代器访问对象元素
  string::iterator it1 = s.begin();
  while (it1 != s.end())
  {
    cout << *it1;
    it1++;
  }
  cout << endl; //CSDN
  //使用迭代器访问对象元素,并对其进行修改
  string::iterator it2 = s.begin();
  while (it2 != s.end())
  {
    *it2 += 1;
    it2++;
  }
  cout << s << endl; //DTEO
  return 0;
}
相关文章
|
24天前
|
存储 安全 C语言
C++ String揭秘:写高效代码的关键
在C++编程中,字符串操作是不可避免的一部分。从简单的字符串拼接到复杂的文本处理,C++的string类为开发者提供了一种更高效、灵活且安全的方式来管理和操作字符串。本文将从基础操作入手,逐步揭开C++ string类的奥秘,帮助你深入理解其内部机制,并学会如何在实际开发中充分发挥其性能和优势。
|
24天前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
2天前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
31 16
|
2天前
|
缓存 安全 Java
《从头开始学java,一天一个知识点》之:字符串处理:String类的核心API
🌱 **《字符串处理:String类的核心API》一分钟速通!** 本文快速介绍Java中String类的3个高频API:`substring`、`indexOf`和`split`,并通过代码示例展示其用法。重点提示:`substring`的结束索引不包含该位置,`split`支持正则表达式。进一步探讨了String不可变性的高效设计原理及企业级编码规范,如避免使用`new String()`、拼接时使用`StringBuilder`等。最后通过互动解密游戏帮助读者巩固知识。 (上一篇:《多维数组与常见操作》 | 下一篇预告:《输入与输出:Scanner与System类》)
31 11
|
8天前
|
Java
课时14:Java数据类型划分(初见String类)
课时14介绍Java数据类型,重点初见String类。通过三个范例讲解:观察String型变量、&quot;+&quot;操作符的使用问题及转义字符的应用。String不是基本数据类型而是引用类型,但使用方式类似基本类型。课程涵盖字符串连接、数学运算与字符串混合使用时的注意事项以及常用转义字符的用法。
|
6天前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
42 6
|
27天前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
24天前
|
存储 缓存 C++
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
|
8天前
|
存储 JavaScript Java
课时44:String类对象两种实例化方式比较
本次课程的主要讨论了两种处理模式在Java程序中的应用,直接赋值和构造方法实例化。此外,还讨论了字符串池的概念,指出在Java程序的底层,DOM提供了专门的字符串池,用于存储和查找字符串。 1.直接赋值的对象化模式 2.字符串池的概念 3.构造方法实例化
|
16天前
|
存储 算法 C++
【c++丨STL】priority_queue(优先级队列)的使用与模拟实现
本文介绍了STL中的容器适配器`priority_queue`(优先级队列)。`priority_queue`根据严格的弱排序标准设计,确保其第一个元素始终是最大元素。它底层使用堆结构实现,支持大堆和小堆,默认为大堆。常用操作包括构造函数、`empty`、`size`、`top`、`push`、`pop`和`swap`等。我们还模拟实现了`priority_queue`,通过仿函数控制堆的类型,并调用封装容器的接口实现功能。最后,感谢大家的支持与关注。
52 1