【C++】String常见函数用法

简介: 【C++】String常见函数用法

一、string类对象的常见构造

       我们可采取以下的方式进行构造,以下是常用的接口:

//生成空字符串
string;   
//拷贝构造函数
string(const string& str);
//用C-string来构造string类对象
string(const char* s);
//string类对象中包含n个字符c
string(size_t n, char c);
#include<string.h>
#include<iostream>
using namespace std;
 
void test1()
{
  string s1;    
  string s2("123456");
  string s3(s2);
  string s4(5, 'c');
  cout << s1 << endl;
  cout << s2 << endl;
  cout << s3 << endl;
  cout << s4 << endl;
}
 
int main()
{
  test1();
  return 0;
}

二、string类对象的容量操作

       这里主要对:size、length、capacity、resize、reserve来进行讲解。

       size与length大家都可顾名思义猜出其用途,即:返回String的大小。

       capacity:大家都有学习过顺序表的经验,也可得出其为该容器的容量。

       resize:将字符串的大小调整为长度为 n 个字符。

       clear:清除字符串的内容,使其变为一个空字符串(长度为 0 个字符)。这意味着将字符串中的所有字符都删除,使其不包含任何字符,长度为零。

// 测试string容量相关的接口
// size/clear/resize
void Teststring1()
{
  // 注意:string类对象支持直接用cin和cout进行输入和输出
  string s("hello, C++!!!");
  cout << s.size() << endl;
  cout << s.length() << endl;
  cout << s.capacity() << endl;
  cout << s << endl;
 
  // 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
  s.clear();
  cout << s.size() << endl;
  cout << s.capacity() << endl;
 
  // 将s中有效字符个数增加到10个,多出位置用'a'进行填充
  // “aaaaaaaaaa”
  s.resize(10, 'a');
  cout << s.size() << endl;
  cout << s.capacity() << endl;
 
  // 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充
  // "aaaaaaaaaa\0\0\0\0\0"
  // 注意此时s中有效字符个数已经增加到15个
  s.resize(15);
  cout << s.size() << endl;
  cout << s.capacity() << endl;
  cout << s << endl;
 
  // 将s中有效字符个数缩小到5个
  s.resize(5);
  cout << s.size() << endl;
  cout << s.capacity() << endl;
  cout << s << endl;
}

  从该运行结果我们可以得出这个结论:在VS编译器下resize在任何情况下都不会进行缩容!

       reserve:请求更改容量。它指的是让字符串的容量适应计划中的大小更改,使其长度最多达到 n 个字符。如果 n 大于当前字符串的容量,该函数会导致容器将其容量增加到 n 个字符(或更多)。在其他所有情况下,这被视为一个非约束性的收缩字符串容量的请求:容器的实现可以自由进行其他优化,并使字符串的容量大于 n。

       接下来,我们对其进行测试:

void Teststring2()
{
  string s;
  // 测试reserve是否会改变string中有效元素个数
  s.reserve(100);
  cout << s.size() << endl;
  cout << s.capacity() << endl;
 
  // 测试reserve参数小于string的底层空间大小时,是否会将空间缩小
  s.reserve(50);
  cout << s.size() << endl;
  cout << s.capacity() << endl;
}

       我们可以看到:reserve与resize一样,在任何情况下都不会缩容!

三、string类对象的遍历操作

       对于string的访问,这里提供三种方式:

       1. 利用库里的重载[]直接进行访问。

       2.利用迭代器进行访问。

       3.利用范围for(其本质还是迭代器)

void Teststring3()
{
  string s1("hello C++");
  const string s2("Hello C++");
  cout << s1 << " " << s2 << endl;
  cout << s1[0] << " " << s2[0] << endl;
 
  s1[0] = 'H';
  cout << s1 << endl;
 
  // s2[0] = 'h';   代码编译失败,因为const类型对象不能修改
 
  string s("hello Bit");
  // 3种遍历方式:
  // 需要注意的以下三种方式除了遍历string对象,还可以遍历是修改string中的字符,
  // 另外以下三种方式对于string而言,第一种使用最多
  // 1. for+operator[]
  for (size_t i = 0; i < s.size(); ++i)
    cout << s[i] << endl;
 
  // 2.迭代器
  string::iterator it = s.begin();
  while (it != s.end())
  {
    cout << *it << endl;
    ++it;
  }
 
  // string::reverse_iterator rit = s.rbegin();
  // C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型
  auto rit = s.rbegin();
  while (rit != s.rend())
    cout << *rit << endl;
 
  // 3.范围for
  for (auto ch : s)
    cout << ch << endl;
}

四、string类对象的修改操作

       push_back:在字符串后尾插字符c append在字符串后追加一个字符串

       operator+= :在字符串后追加字符串str c_str(重点)返回C格式字符串

      find + npos:从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置

       substr:在str中从pos位置开始,截取n个字符,然后将其返回

void Teststring4()
{
  string str;
  str.push_back(' ');   // 在str后插入空格
  str.append("hello");  // 在str后追加一个字符"hello"
  str += 'C';           // 在str后追加一个字符'C'   
  str += "++";          // 在str后追加一个字符串"++"
  cout << str << endl;
  cout << str.c_str() << endl;   // 以C语言的方式打印字符串
 
  // 获取file的后缀
  string file("string.cpp");
  size_t pos = file.rfind('.');
  string suffix(file.substr(pos, file.size() - pos));
  cout << suffix << endl;
 
  // npos是string里面的一个静态成员变量
  // static const size_t npos = -1;
 
  // 取出url中的域名
  string url("http://www.cplusplus.com/reference/string/string/find/");
  cout << url << endl;
  size_t start = url.find("://");
  if (start == string::npos)
  {
    cout << "invalid url" << endl;
    return;
  }
  start += 3;
  size_t finish = url.find('/', start);
  string address = url.substr(start, finish - start);
  cout << address << endl;
 
  // 删除url的协议前缀
  pos = url.find("://");
  url.erase(0, pos + 3);
  cout << url << endl;
}

五、vs下string的结构

        string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字符串的存储空间: 当字符串长度小于16时,使用内部固定的字符数组来存放 当字符串长度大于等于16时,从堆上开辟空间

 union _Bxty { // storage for small buffer or pointer to larger one
     // This constructor previously initialized _Ptr. Don't rely on the new behavior without
     // renaming `_String_val` (and fixing the visualizer).
     _CONSTEXPR20 _Bxty() noexcept : _Buf() {} // user-provided, for fancy pointers
     _CONSTEXPR20 ~_Bxty() noexcept {} // user-provided, for fancy pointers
 
     value_type _Buf[_BUF_SIZE];
     pointer _Ptr;
     char _Alias[_BUF_SIZE]; // TRANSITION, ABI: _Alias is preserved for binary compatibility (especially /clr)
 };
 _Bxty _Bx;

        这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。

       其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量 最后:还有一个指针做一些其他事情。 故总共占16+4+4+4=28个字节。

完!


相关文章
|
3天前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
16 3
|
3天前
|
编译器 C语言 C++
详解C/C++动态内存函数(malloc、free、calloc、realloc)
详解C/C++动态内存函数(malloc、free、calloc、realloc)
21 1
|
3天前
|
存储 编译器 C++
C++入门3——类与对象2-1(类的6个默认成员函数)
C++入门3——类与对象2-1(类的6个默认成员函数)
14 1
|
3天前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
14 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
5天前
|
存储 编译器 程序员
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
【C++篇】手撕 C++ string 类:从零实现到深入剖析的模拟之路
30 2
|
3天前
|
C语言 C++
C++番外篇——string类的实现
C++番外篇——string类的实现
16 0
|
3天前
|
C++ 容器
C++入门7——string类的使用-2
C++入门7——string类的使用-2
14 0
|
3天前
|
C语言 C++ 容器
C++入门7——string类的使用-1
C++入门7——string类的使用-1
17 0
|
5天前
|
安全 编译器 程序员
【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略
【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略
19 2
|
5天前
|
存储 C++
【C++篇】C++类和对象实践篇——从零带你实现日期类的超详细指南
【C++篇】C++类和对象实践篇——从零带你实现日期类的超详细指南
15 2
【C++篇】C++类和对象实践篇——从零带你实现日期类的超详细指南