C++入门7——string类的使用-2

简介: C++入门7——string类的使用-2

4. string类对象的容量操作

4.1 string中有效字符个数(size与length)

size与length返回字符串有效字符长度(不包含\0)

前面已经说过,size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。

代码演示:

int main()
{
  string s1("hello world!");
  cout << s1.size() << endl;
  return 0;
}

4.2 string的当前容量(capacity)

capacity返回空间总大小

代码如下:

int main()
{
  string s1("hello world!");
  cout << s1.capacity() << endl;
  return 0;
}

设计程序检测string的扩容机制:

int main()
{
  string s1("hello world!");
  //检测string的扩容机制
  size_t old = s1.capacity();    //令old=原本的容量大小
  cout << old << endl;        
  for (size_t i = 0; i < 500; i++)
  {
    s1.push_back('l');         //尾插l的过程中string的容量大小一定会发生变化
    if (old != s1.capacity())  //当发生扩容时,打印新的string容量大小
    {
      cout << s1.capacity() << endl;
      old = s1.capacity();
    }
  }
  return 0;
}

4.3 string提前开空间(reserve)

reserve为字符串预留空间(即可以理解为需要多少空间提前开好,不用边用边开)

reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小。(在vs2019下reserve只扩容不缩容,在g++下reserve会缩容,但只会缩到现有数据的大小)

用法如下:

int main()
{
  string s1("hello world!");
  cout << s1.capacity() << endl;
  s1.reserve(500);
  cout << s1.capacity() << endl;
  return 0;
}

4.4 string提前开空间并初始化(resize)

resize将有效字符的个数改变成n个,多出的空间用字符c填充

resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字 符个数增多时:resize(n)用'\0'来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大 小,如果是将元素个数减少,底层空间总大小不变。

①如果要扩容的空间>capacity,则扩容+尾插。验证如下:

int main()
{
  string s1("hello world!");
  cout << s1.size() << endl;
  cout << s1.capacity() << endl;
 
  //如果要扩容的空间>capacity
  s1.resize(100);
  cout << s1.size() << endl;
  cout << s1.capacity() << endl;
  cout << s1 << endl;
  return 0;
}

int main()
{
  string s1("hello world!");
  cout << s1.size() << endl;
  cout << s1.capacity() << endl;
 
  //如果要扩容的空间>capacity
  s1.resize(100, 'x');
  cout << s1.size() << endl;
  cout << s1.capacity() << endl;
  cout << s1 << endl;
  return 0;
}

②如果size<n<capacity,则只尾插不扩容,验证如下:

int main()
{
  string s1("hello world!");
  cout << s1.size() << endl;
  cout << s1.capacity() << endl;
 
  //如果size<n<capacity
  s1.resize(13,'x');
  cout << s1.size() << endl;
  cout << s1.capacity() << endl;
  cout << s1 << endl;
  return 0;
}

③如果n<size,只删除、保留前n个,不缩容,验证如下:

int main()
{
  string s1("hello world!");
  cout << s1.size() << endl;
  cout << s1.capacity() << endl;
 
  //如果n<capacity
  s1.resize(6);
  cout << s1.size() << endl;
  cout << s1.capacity() << endl;
  cout << s1 << endl;
  return 0;
}

(reserve与resize的区别可以概括为一句话:reserve只影响容量,不影响数据,resize既影响容量又影响数据)

4.5 清空string所有字符(clear)

清空有效字符

clear()只是将string中有效字符清空,不改变底层空间大小。

验证如下:

int main()
{
  string s1("hello world!");
  cout << s1.size() << endl;
  cout << s1.capacity() << endl;
 
  s1.clear();
  cout << s1.size() << endl;
  cout << s1.capacity() << endl;
  cout << s1 << endl;
  return 0;
}

4.6 判断string是否为空(empty)

检测字符串释放为空串,是返回true,否则返回false(注意:空为真,不空为假)

验证如下:

int main()
{
  string s1("hello world!");
  cout << s1.empty() << endl;
  string s2;
  cout << s2.empty() << endl;
  return 0;
}

5.string类对象的修改操作

修改操作无非就是增删查改,这里只介绍比较常用的操作

5.1 增

1. append插入

增操作其实已经有了一个我们熟悉的push_back,可是push_back每次只能尾插一个字符,为了方便就有了append:

比如我们二者兼用:

int main()
{
  string s1("hello");
  s1.push_back(' ');
  s1.append("world!");
  cout << s1 << endl;
  return 0;
}

append的其他常用用法如下:

①string& append (const char* s);插入常量字符串(上面的用法)

②string& append (const string& str);插入string:

int main()
{
  string s1("hello");
  string s2(s1);
  return 0;
}

③string& append (const string& str, size_t subpos, size_t sublen);插入string从subpos位置起到sublen个字符止的那部分:

int main()
{
  string s1("hello world!");
  string s2(s1,1,3);
  return 0;
}

④string& append (const char* s, size_t n);插入常量字符串的前n个:

int main()
{
  string s1("hello world!", 3);
  return 0;
}

⑥string& append (size_t n, char c);插入n个字符c:

int main()
{
  string s1(4,'x');
  return 0;
}

⑦string& append (InputIterator first, InputIterator last);插入string的一部分:

插入s1:

int main()
{
  string s1("hello world!");
  string s2;
  s2.append(s1.begin(), s1.end());
  return 0;
}

插入去头去尾的s1:

int main()
{
  string s1("hello world!");
  string s2;
  s2.append(++s1.begin(), --s1.end());
  return 0;
}

2. +=插入

①string& operator+= (const string& str);插入string:

int main()
{
  string s1("hello world!");
  string s2;
  s2 += s1;
  return 0;
}

②string& operator+= (const char* s);插入字符串:

int main()
{
  string s1;
  s1 += "hello world!";
  return 0;
}

③string& operator+= (char c);插入字符:

int main()
{
  string s1;
  s1 += '!';
  return 0;
}

3.insert指定位置插入

观察push_back与append,二者都是尾插,那有没有不是尾插的方法呢?当然有!

①string& insert (size_t pos, const string& str);在pos位置插入string:

int main()
{
  string s1("hello ");
  string s2("world!");
  s2.insert(0, s1);
  return 0;
}

②string& insert (size_t pos, const string& str, size_t subpos, size_t sublen);在pos位置插入string的一部分:

int main()
{
  string s1("hello ");
  string s2("world!");
  s2.insert(0, s1, 1, 3);//ellworld!
  return 0;
}

③string& insert (size_t pos, const char* s);在pos位置插入字符串:

int main()
{
  string s1("world!");
  s1.insert(0, "hello ");//hello world!
  return 0;
}

④string& insert (size_t pos, const char* s, size_t n);在pos位置插入字符串的前n个:

int main()
{
  string s1("world!");
  s1.insert(0, "hello ",3);//helworld!
  return 0;
}

5.2 删

1. 尾删(pop_back)

尾删:

int main()
{
  string s1("hello world!");
  s1.pop_back();//hello world
  return 0;
}

2. 删除指定位置(erase)

①string& erase (size_t pos = 0, size_t len = npos);从第pos个位置删除len个字符:

int main()
{
  string s1("hello world!");
  s1.erase(5, 1);//helloworld!
  return 0;
}

②iterator erase (iterator p);删除string的第p个位置:

int main()
{
  string s1("hello world!");
  s1.erase(s1.begin()+1);//hllo world!
  return 0;
}

5.3 查

1.取string子串(substr)

string substr (size_t pos = 0, size_t len = npos) const;从pos位置开始,取len个字符:

int main()
{
  string s1("hello world!");
  string s2 = s1.substr(6, 5);//world
  return 0;
}

2.查找指定字符(find)

关于find的返回值:

The position of the first character of the first match.

If no matches were found, the function returns string::npos.

即:如果找到了就返回找到的第一个的下标,如果没有找到就返回整型的最大值。

①size_t find (char c, size_t pos = 0) const;从pos位置开始找c,没有给pos默认从头开始找:

int main()
{
  string s1("hello world!");
  size_t pos1 = s1.find('l');//2
  size_t pos2 = s1.find('l', 5);//9
  size_t pos3 = s1.find('x');//npos
  return 0;
}

例:取string指定的一部分:

int main()
{
  //取文件名后缀
  string s1("test.cpp");
  size_t pos1 = s1.find('.');
  if (pos1 != string::npos)
  {
    /*string s2 = s1.substr(pos1, s1.size() - pos1);*/
    string s2 = s1.substr(pos1);
    cout << s2 << endl;
  }
  return 0;
}

5.4 改

1. 修改string指定位置(replace)

①string& replace (size_t pos, size_t len, const string& str);在pos位置的len个字符替换成str:

int main()
{
  string s1("hello world!");
  s1.replace(5, 1, "?");//hello?world!
  return 0;
}

2. string与string交换(swap)

与另一个string交换:

int main()
{
  string s1("hello world!");
  string s2;
  s2.swap(s1);//hello world!
  return 0;
}

5.5 查改结合完成替换操作

例:将s1的空格全部替换为?

方法一:

int main()
{
  string s1("have a good time!");
  cout << "替换前s1=" << s1 << endl;//have a good time!
  size_t pos = s1.find(' ', 0);
  while (pos != string::npos)
  {
    s1.replace(pos, 1, "?");
    pos = s1.find(' ', pos + 1);
  }
  cout << "替换后s1=" << s1 << endl;//have?a?good?time!
  return 0;
}

实际中replace效率太低,因此尽量少用replace

方法二:

int main()
{
  string s1("have a good time!");
  cout << "替换前" << s1 << endl;//have a good time!
  string s2;
  for (auto ch : s1)
  {
    if (ch == ' ')
    {
      s2 += "?";
    }
    else
    {
      s2 += ch;
    }
  }
  s1.swap(s2);
  cout << "替换后" << s1 << endl;//have?a?good?time!
  return 0;
}


相关文章
|
3天前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
3天前
|
C++
模拟实现c++中的string
模拟实现c++中的string
|
1月前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
68 19
|
1月前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
51 13
|
1月前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
53 5
|
1月前
|
存储 算法 搜索推荐
【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】
1. **相关排序和查找算法的原理**:介绍直接插入排序、直接选择排序、冒泡排序和顺序查找的基本原理及其实现代码。 2. **C++ 类与成员函数的定义**:讲解如何定义`Array`类,包括类的声明和实现,以及成员函数的定义与调用。 3. **数组作为类的成员变量的处理**:探讨内存管理和正确访问数组元素的方法,确保在类中正确使用动态分配的数组。 4. **函数参数传递与返回值处理**:解释排序和查找函数的参数传递方式及返回值处理,确保函数功能正确实现。 通过掌握这些知识,可以顺利地将排序和查找算法封装到`Array`类中,并进行测试验证。编程要求是在右侧编辑器补充代码以实现三种排序算法
41 5
|
1月前
|
Serverless 编译器 C++
【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】
本任务要求设计一个矩形类、圆形类和图形基类,计算并输出相应图形面积。相关知识点包括纯虚函数和抽象类的使用。 **目录:** - 任务描述 - 相关知识 - 纯虚函数 - 特点 - 使用场景 - 作用 - 注意事项 - 相关概念对比 - 抽象类的使用 - 定义与概念 - 使用场景 - 编程要求 - 测试说明 - 通关代码 - 测试结果 **任务概述:** 1. **图形基类(Shape)**:包含纯虚函数 `void PrintArea()`。 2. **矩形类(Rectangle)**:继承 Shape 类,重写 `Print
48 4
|
5月前
|
Java 索引
java基础(13)String类
本文介绍了Java中String类的多种操作方法,包括字符串拼接、获取长度、去除空格、替换、截取、分割、比较和查找字符等。
60 0
java基础(13)String类
|
3月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
90 2
|
4月前
|
Java
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性
本文深入探讨了Java中方法参数的传递机制,包括值传递和引用传递的区别,以及String类对象的不可变性。通过详细讲解和示例代码,帮助读者理解参数传递的内部原理,并掌握在实际编程中正确处理参数传递的方法。关键词:Java, 方法参数传递, 值传递, 引用传递, String不可变性。
93 1
【编程基础知识】(讲解+示例实战)方法参数的传递机制(值传递及地址传递)以及String类的对象的不可变性