发布时间:2025-06-24 17:31:13  作者:北方职教升学中心  阅读量:579


img

最后我们来谈谈empty()函数,它主要用来判断字符串是否为空:

voidTestEmpty(){string s1("");//空串string s2("hello ");if(s1.empty()){cout <<"s1为空串"<<endl;}else{cout <<"s1不为空串"<<endl;}if(s2.empty()){cout <<"s2为空串"<<endl;}else{cout <<"s2不为空串"<<endl;}}

img

2.3.2. 有效长度与容量操作

首先我们要介绍的就是clear()函数,他能清空字符串,也就是改变有效长度size,但不会改变容量capacity。它提供了一种统一的方式来访问容器中的元素,而无需关心容器的具体实现细节。·

函数名称功能
c_str返回C格式的字符串
substr从字符串pos位置开始,截取n个字符,然后将其返回
find从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
find_first_of在原字符串中,从前往后找匹配串中第一个匹配的字符
find_last_of在原字符串中,从后往前找匹配串中第一个匹配的字符
find_first_not_of在原字符串中,从前往后找匹配串中第一个不匹配的字符
find_last_not_of在原字符串中,从后往前找匹配串中第一个不匹配的字符
getline获取一行字符串
operator<<流提取重载
operator>>流插入重载

首先是substrfind函数,这两个函数可以结合使用

voidTest15(){string s("hello betty!");//在字符串s中寻找bsize_t pos =s.find('b');//从下标6开始截取长度为6的字符串string str =s.substr(pos,6);cout <<str <<endl;}

img

find_first_offind_last_offind_first_not_offind_last_not_of的用法非常类似,我们就只以其中一种举例:

voidTest16(){string str("Please, replace the vowels in this sentence by asterisks.");//从str字符串中任意匹配aeiousize_t found =str.find_first_of("aeiou");//找不到返回nposwhile(found !=string::npos){str[found]='*';//从下一个位置找found =str.find_first_of("aeiou",found +1);}cout <<str <<endl;}

img

这里是findfind_first_of详细的接口,大家可以根据实际需求参考使用

img

img

最后我们来介绍以下getline,它与流插入都是读取字符串,但是区别就是getline遇见空格不会停止,而流插入会。

img

voidTest11(){string s1("hello betty!");cout <<s1.front()<<endl;cout <<s1.back()<<endl;}

img

2.5. string的修改操作

string关于修改的函数的接口都比较多,一一列举比较麻烦,这里我们只重点介绍常用的接口,剩下的大家具体使用时查官方文档即可。而max_size返回字符串最大容量,不同平台下大小可能不一样。两个函数的效果有何不同呢?

voidTest8(){string s1("hello world!");cout <<"reserve测试:"<<endl;cout <<s1 <<endl;cout <<"s1的有效长度为:"<<s1.size()<<endl;cout <<"s1的容量大小为:"<<s1.capacity()<<endl;s1.reserve(5);cout <<s1 <<endl;cout <<"s1的有效长度为:"<<s1.size()<<endl;cout <<"s1的容量大小为:"<<s1.capacity()<<endl;s1.reserve(13);cout <<s1 <<endl;cout <<"s1的有效长度为:"<<s1.size()<<endl;cout <<"s1的容量大小为:"<<s1.capacity()<<endl;s1.reserve(25);cout <<s1 <<endl;cout <<"s1的有效长度为:"<<s1.size()<<endl;cout <<"s1的容量大小为:"<<s1.capacity()<<endl;cout <<endl;cout <<"resize测试:"<<endl;string s2("hello world!");cout <<s2 <<endl;cout <<"s2的有效长度为:"<<s2.size()<<endl;cout <<"s2的容量大小为:"<<s2.capacity()<<endl;s2.resize(5);cout <<s2 <<endl;cout <<"s2的有效长度为:"<<s2.size()<<endl;cout <<"s2的容量大小为:"<<s2.capacity()<<endl;s2.resize(10,'x');cout <<s2 <<endl;cout <<"s2的有效长度为:"<<s2.size()<<endl;cout <<"s2的容量大小为:"<<s2.capacity()<<endl;s2.resize(25,'x');cout <<s2 <<endl;cout <<"s2的有效长度为:"<<s2.size()<<endl;cout <<"s2的容量大小为:"<<s2.capacity()<<endl;}

img

通过上述实验,我们可以总结出以下规律:

  1. n<sz时,reserve并不会发生任何改变,resize会删除有效字符到指定大小。它们之间不小的差别,首先它们的接口如下

    img

    我假设字符串原来有效长度为sz,那么如果n<szsz<n<capcityn>capacity

begin()end()具体指向情况如下图所示:

img

然后我们可以通过以下代码来演示效果:

voidTest3(){string s1 ="hello betty!";//普通迭代器string::iterator it =s1.begin();//指向第一个位置while(it !=s1.end()){cout <<*it <<" ";++it;}cout <<endl;conststring s2 ="hello betty!";//const对象//const 反向迭代器 不能改变字符串中的值string::const_iterator itt =s2.begin();//指向最后一个字符的下一个位置while(itt !=s2.end()){cout <<*itt <<" ";++itt;}}

img

2.1.2. rbegin()与rend()函数

rbegin()rend()函数的使用方法具体如下:

  1. 函数声明:
  • reverse_iterator rbegin();
  • const_reverse_iterator rbegin() const;
  1. 作用:返回指向字符串最后一个字符位置(即其反向开头)的反向迭代器。

  2. n>capacity时,reserve会发生扩容,resize会补充有效字符(默认为’\0)到指定大小。string s6(7,'a');//7. 使用的是某段迭代器区间初始化。string s4("hello world!");//5. 使用的是某个字符数组前n个字符来初始化string s5("hello world!",5);//6. 使用的是n个c字符初始化。

    string类中,我们就可以通过迭代器来访问其具体元素,并且也为我们提供了相应的调用函数。

    voidTestClear(){string s1("hello world!");cout <<"s1的有效长度为:"<<s1.size()<<endl;cout <<"s1的容量大小为:"<<s1.capacity()<<endl;s1.clear();cout <<"s1的有效长度为:"<<s1.size()<<endl;cout <<"s1的容量大小为:"<<s1.capacity()<<endl;if(s1.empty()){cout <<"s1是空串"<<endl;}}

    img

    接下来我们将介绍两个可以改变容量的函数reserveresize。对于我们迭代器,我们在使用时将其当做指针使用即可。

  3. 返回值:普通对象返回iterator迭代器,const 对象返回const_iterator迭代器。
  4. 最后我们来介绍一个C++11引入的一个可以缩容的函数shrink_to_fit**,**它的主要目的就是让有效长度size与容量capacity适配。string s3(s2,1,7);//4. 使用的是某个字符数组初始化。

    ✨✨ 欢迎大家来到贝蒂大讲堂✨✨

    🎈🎈养成好习惯,先赞后看哦~🎈🎈

    所属专栏:C++学习
    贝蒂的主页:Betty’s blog

    1. C/C++中的字符串

    1.1. C语言中的字符串

    在 C 语言中,字符串是由字符组成的字符数组,以空字符 '\0'作为结束标志。

  5. 第五个使用的是某个字符数组前n个字符来初始化
  6. 第六个使用的是nc字符初始化。
  7. 第四个使用的是某个字符数组初始化。
  • 注意:不同平台下扩容效果可能会不同,但是这个规律是不会改变的。
  • 最后也能通过赋值运算符重载初始化。
  • 返回值:普通对象返回iterator迭代器,const 对象返回const_iterator迭代器。

    voidTest1(){char*str =NULL;intlen =0;// 初始分配一些内存str =(char*)malloc(10*sizeof(char));if(str ==NULL){perror("malloc fail");return1;}strcpy(str,"Hello");len =strlen(str);// 根据需要扩展字符串str =(char*)realloc(str,(len +6)*sizeof(char));if(str ==NULL){perror("realloc fail");return1;}strcat(str," World");printf("%s\n",str);//最后释放内存free(str);}

    1.2. C++中的字符串

    虽然C++兼容C语言,在C++中仍然可以使用C语言的字符串,但是C++自己实现了一个关于处理字符串的类–string,它提供了许多方便的操作和功能,使得字符串的处理更加安全和高效。而string中的swap函数实现的是指针交换,效率明显高的多。

    img

    voidTestSwap(){string s("hello betty!");string p("hello world!");cout <<s <<endl;cout <<p <<endl;s.swap(p);cout <<s <<endl;cout <<p <<endl;}

    img

    2.6. string的其他操作

    除了上面操作外,string还有一些格外补充操作,这里值挑几个常用的函数为大家介绍。

    voidTest9(){string s1("hello world!");cout <<s1 <<endl;cout <<"s1的有效长度为:"<<s1.size()<<endl;cout <<"s1的容量大小为:"<<s1.capacity()<<endl;s1.reserve(100);//先扩容cout <<"扩容后s1的有效长度为:"<<s1.size()<<endl;cout <<"扩容后s1的容量大小为:"<<s1.capacity()<<endl;s1.shrink_to_fit();//再缩容cout <<"缩容后s1的有效长度为:"<<s1.size()<<endl;cout <<"缩容后s1的容量大小为:"<<s1.capacity()<<endl;}

    img

    2.4. string的访问操作

    接下来我们就来介绍string常见的访问函数:

    函数名称功能
    operator[]返回指定位置的字符,越界则报错
    at返回指定位置的字符,越界则抛异常
    back返回字符串最后一个字符(不是’\0’)
    front返回字符串第一个字符

    首先是operator[]这个运算符重载与at函数,它们的功能类似都是返回指定下标字符,并且char*类型返回char*类型,const char*类型返回const char*类型。

    2. string的接口

    C++为我们提供了丰富的string接口,我们可以通过对象来调用,为了方便我们学习我们可以通过查询相关文档辅助–string类的接口介绍

    img

    2.1. string的迭代器

    迭代器(Iterator)是一种用于遍历容器中元素的工具。string s2(s1);//3. 使用一个string的某段区间初始化,其中pos是字符串下标,npos是指无符号整数的最大值。

  • 第七个使用的是某段迭代器区间初始化。

    img

    voidTest10(){string s1("hello betty!");for(inti =0;i <s1.size();i++){cout <<s1[i]<<" ";}cout <<endl;for(inti =0;i <s1.size();i++){cout <<s1.at(i)<<" ";}}

    img

    然后就是C++11引入的frontback函数,但实用性不是特别大,大家只需要了解。所以扩容倍数是

    img

    不确定的,具体由不同编译器决定。

    接下来我们可以来探究一下string的扩容机制

    voidTestCapacity(){string s;size_t sz =s.capacity();cout <<"making s grow:\n";for(inti =0;i <100;++i){s.push_back('c');if(sz !=s.capacity()){sz =s.capacity();cout <<"capacity changed: "<<sz <<'n';}}}

    VS2022编译器中,string大概是以1.5倍扩容,但是在g++编译器中却是2倍扩容。

    //数组大小为20charstr[20]="hello betty!\n";

    当然我们可以通过动态内存分配来来解决这个问题,但无疑非常繁琐。下面是常见的关于string修改的函数接口:

    函数名称功能
    push_back在字符串后追加字符
    operator+=在字符串后追加字符或字符串
    append在字符串后追加字符串
    insert在指定位置追加字符或者字符串
    assign使用指定字符串替换原字符串
    replace用新字符串替换原字符串指定区间
    pop_back删除字符串最后一个字符
    erase删除字符串指定部分
    swap交换两个字符串
    2.5.1. 字符串的增加

    首先我们来介绍字符串的增加操作,在末尾添加字符我们可以使用push_back,在末尾添加字符串我们可以使用append,而operator+=既可以在末尾添加字符,也可以添加字符串,insert可以在任意位置追加字符或者字符串。由于数组特点,字符串的大小在定义数组时就已经确定,无法更改。

  • 下面是具体的代码示例:

    voidTest5(){//1. 使用我们的默认构造函数,不需要传参。而在VS2022下大小为2147483647,也就是INT_MAX的大小。
  • 第二个使用的是拷贝构造来初始化。

  • 返回值:普通对象返回iterator迭代器,const 对象返回const_iterator迭代器。以下就是我们常见初始化的接口:

    img

    1. 第一个使我们的默认构造函数,不需要传参。接下来我们将详细介绍C++string类的特点与用法。

      2.3. string的容量操作

      接下来我们将学习关于string类常见的容量操作:

      函数名称功能
      size返回字符串的有效长度
      length返回字符串的有效长度
      capacity返回字符串的容量大小
      max_size返回字符串的最大长度
      clear清空字符串
      empty检查是否为空串,是则返回ture,否则返回false
      reserve请求改变字符串的容量
      resize重新设置有效字符的数量,超过原来有效长度则用c字符填充
      shrink_to_fit收缩资字符串容量
      2.3.1. 有效长度与容量大小

      string类中,我们可以通过size()length()返回字符串的有效长度;capacity()返回字符串的容量,其具体效果如下图:

      img

      我们也可以通过代码来验证:

      voidTest6(){string s("hello betty!");cout <<s.size()<<endl;//有效长度cout <<s.length()<<endl;//有效长度cout <<s.capacity()<<endl;//容量大小cout <<s.max_size()<<endl;//最大大小}

      img

      其中有效长度size以及容量大小capacity不包括\0。string s1;s1 ="hello betty!";//2. 使用的是拷贝构造来初始化。

    2. 返回值:普通对象返回iterator迭代器,const 对象返回const_iterator迭代器。

    rbegin()rend()具体指向情况如下图所示:

    img

    然后我们可以通过以下代码来演示效果:

    voidTest4(){string s1 ="hello betty!";//普通反向迭代器string::reverse_iterator rit =s1.rbegin();//指向最后一个字符位置while(rit !=s1.rend()){cout <<*rit <<" ";++rit;}cout <<endl;conststring s2 ="hello betty!";//const对象//const 反向迭代器 不能改变字符串中的值string::const_reverse_iterator ritt =s1.rbegin();//指向最后一个字符的位置while(ritt !=s1.rend()){cout <<*ritt <<" ";++ritt;}}

    img

    2.2. string的初始化与销毁

    因为string是一个类,所以我们在初始化时肯定调用其构造函数初始化。

  • sz<n<capcity时,reserve并不会发生任何改变,resize会补充有效字符(默认为’\0)到指定大小。下面是一个简单的string的使用:

    voidTest2(){string str ="hello betty!";cout <<str <<endl;//改变第一个字符str[0]++;cout <<str <<endl;//在末尾添加一个字符str +='e';cout <<str <<endl;//在末尾添加一个字符串str +=" hello";cout <<str <<endl;}

    img

    相较于C语言的字符串,C++的字符串明显方便的多。

    voidTest14(){string s("hello betty!");//删除最后一个字符s.pop_back();cout <<s <<endl;//删除迭代器所指字符s.erase(s.begin());cout <<s <<endl;//删除0下标长度为3的一段区间s.erase(0,3);cout <<s <<endl;//删除一段迭代器区间s.erase(s.begin(),s.end()-2);cout <<s <<endl;}

    img

    2.5.4. 字符串的交换

    最后我们来介绍一个字符串的交换函数swap,这个swap函数与算法库中的swap函数并不相同,算法库中的swap函数将string中每个具体值都交换。

    2.1.1. begin()与end()函数

    begin()end()函数的使用方法具体如下:

    1. 函数声明:
    • iterator begin();
    • const_iterator begin() const;
    1. 作用:返回指向字符串第一个字符的迭代器。

      voidTest13(){string s1("hello world!");string s2;//直接用s1替换s2s2.assign(s1);cout <<s2 <<endl;//用s1的某段区间替换s2s2.assign(s1,6);cout <<s2 <<endl;string s3("i am betty!");//用s1替换掉2下标长度为2的区间s3.replace(2,2,s1);cout <<s3 <<endl;//用字符数组前n个字符替换s3.replace(0,2,"hhhh",2);cout <<s3 <<endl;}

      img

      当然assignreplace的接口不止这些,下面是具体的的接口,需要时直接插文档即可

      img

      img

      2.5.3. 字符串的删除

      字符串的删除有支持删除最后一个字符的pop_back,也有支持删除任意区间的erase。这区别和C语言中scanfgets类似

      img
      img

voidTest12(){string s("hello betty!");//追加一个!s.push_back('!');cout <<s <<endl;s +='!';cout <<s <<endl;s.insert(0,1,'!');cout <<s <<endl;//追加一个字符串s.append("hello ");cout <<s <<endl;s+="world!";cout <<s <<endl;//在下标0处追加字符串s.insert(0,"hello ");cout <<s <<endl;}

img

当然appendinsert的接口不止这些,下面是具体的的接口,需要时直接插文档即可

img

img

2.5.2. 字符串的替换

接下来我们来介绍两个字符串替换的函数assign以及replace,其中assign是直接替换掉原字符串,而replace是替换原字符串的某段区间。

  1. 函数声明:
  • reverse_iterator rend();
  • const_reverse_iterator rend() const;
  1. 作用:返回指向字符串第一个字符前面一个位置的反向迭代器。

  1. 函数声明:
  • iterator end();
  • const_iterator end() const;
  1. 作用:返回指向字符串最后一个字符下一个位置的迭代器。string s7(s1.begin(),s1.end());//赋值运算符重载初始化string s8 ="hello betty!";cout <<s1 <<endl;cout <<s2 <<endl;cout <<s3 <<endl;cout <<s4 <<endl;cout <<s5 <<endl;cout <<s6 <<endl;cout <<s7 <<endl;cout <<s8 <<endl;}

    img

    而由于string是一个类,出了作用域会自动调用它的析构函数,所以不用显示调用。

  2. 第三个是使用一个string的某段区间初始化,其中pos是字符串下标,npos是指无符号整数的最大值。