从零开始的C++学习生活 6:string的入门使用

个人主页:Yupureki-CSDN博客

C++专栏:C++_Yupureki的博客-CSDN博客

目录

前言

[1. 为什么学习string类?](#1. 为什么学习string类?)

[1.1 C语言字符串的局限性](#1.1 C语言字符串的局限性)

[1.2 字符串的重要性](#1.2 字符串的重要性)

[2. 标准库中的string类](#2. 标准库中的string类)

[2.1 string类基础](#2.1 string类基础)

[2.2 C++11新特性:auto和范围for](#2.2 C++11新特性:auto和范围for)

auto关键字

范围for循环

[3. string基本操作](#3. string基本操作)

构造字符串

容量操作

[4 string访问和遍历](#4 string访问和遍历)

访问

遍历

[5. string的修改操作](#5. string的修改操作)

[6. string类的模拟实现](#6. string类的模拟实现)

[6.1 浅拷贝问题](#6.1 浅拷贝问题)

[6.2 深拷贝解决方案](#6.2 深拷贝解决方案)

结语


前言

在C++编程中,字符串处理是我们日常开发中最常见的任务之一。C语言中,我们使用字符数组和\0结尾的方式来处理字符串,但这种方式存在诸多不便:需要手动管理内存、容易发生越界访问、功能有限且不符合面向对象的思想。

C++标准库中的string类彻底改变了这一局面,它封装了字符串的存储和操作,提供了丰富而安全的接口,让我们能够更加高效、安全地处理字符串。无论是算法竞赛、日常开发还是面试求职,string类都是我们必须掌握的重要工具。

本文将全面介绍C++ string类的使用方法和实现原理,帮助大家深入理解并熟练运用这个强大的工具。

1. 为什么学习string类?

1.1 C语言字符串的局限性

在C语言中,字符串是以\0结尾的字符数组,虽然标准库提供了一系列字符串操作函数,但存在明显问题:

cpp 复制代码
char str[20] = "hello";
strcat(str, " world");  // 需要确保数组足够大,否则可能越界

并且在C语言中,字符串的处理相关的函数极少。如果现在我要求你对"hello world"进行以下操作:在'e'前面插入5个'x',删除第一个'l',找到字符串中第一个'o',删除所有的' ',最后将字符串再改回"hello world"。你看到这,似乎并不是很难,但是特别麻烦。每一个要求都需要十几行的代码,如果加在一起便十分复杂。

那么string就解决了这个问题,因为集成了我们所需的几乎所有处理字符串的操作函数

1.2 字符串的重要性

https://www.nowcoder.com/practice/1277c681251b4372bdef344468e4f26e?tpId=13&&tqId=11202&rp=6&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking

https://leetcode-cn.com/problems/add-strings/

在OJ中,有关字符串的题目基本以string类的形式出现,并且在竞赛中,对于字符串的处理也十分频繁,如果在C中死板的一行行写,那么就十分低效

2. 标准库中的string类

2.1 string类基础

string为C++中十分重要的一个板块,为此我们专门在专业的C++相关文档中查阅并讲解

http://www.cplusplus.com/reference/string/string/?kw=string

同时在使用string类时,必须包含#include头文件以及using namespace std;

2.2 C++11新特性:auto和范围for

auto关键字

auto让编译器自动推导变量类型,使代码更简洁

cpp 复制代码
 int main()
 {
 int a = 10;
 auto b = a;
 auto c = 'a';//auto根据赋值的类型,自动推导变量的类型,因此auto的变量必须初始化
 auto d = func1()
}

范围for循环

使用auto简化容器遍历:

cpp 复制代码
string str = "hello";
// 传统遍历
for (size_t i = 0; i < str.size(); ++i) {
    cout << str[i];
}

// 范围for遍历
for (auto ch : str) {
    cout << ch;  // 自动遍历每个字符
}

// 如果需要修改字符串,使用引用
for (auto& ch : str) {
    ch = toupper(ch);  // 将字符转为大写
}

3. string基本操作

构造字符串

string是个,因此具有构造函数

cpp 复制代码
string s1;              // 空字符串
string s2("hello");     // 用C字符串构造
string s3(s2);          // 拷贝构造
string s4(5, 'A');      // "AAAAA"
string s5 = "world";    // 赋值构造

容量操作

函数名称

size(重点) 返回字符串有效字符长度

length 返回字符串有效字符长度

capacity 返回空间总大小

empty (重点) 检测字符串释放为空串,是返回true,否则返回false

clear (重点) 清空有效字符

reserve (重点)为字符串预留空间**

resize (重点) 将有效字符的个数该成n个,多出的空间用字符c填充

cpp 复制代码
string str = "hello";
cout << str.size();     // 5,返回有效字符长度
cout << str.length();   // 5,与size()相同
cout << str.capacity(); // 返回总容量
cout << str.empty();    // 是否为空

str.clear();            // 清空字符串
str.resize(10, 'x');    // 调整大小,多出部分用'x'填充
str.reserve(100);       // 预留空间,提高效率

4 string访问和遍历

访问

string重载了operator[],使其能够像操作数组一样利用[]来访问元素

cpp 复制代码
int main ()
{
  std::string str ("Test string");
  for (int i=0; i<str.length(); ++i)
  {
    std::cout << str[i];//利用[]和下标来访问元素
  }
  return 0;
}

遍历

begin和end

begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器

cpp 复制代码
string str = "hello";


// 迭代器
for (auto it = str.begin(); it != str.end(); ++it) {
    cout << *it;//从左到右访问->hello
}

rbegin和rend

rbegin获取一个字符的反向迭代器 + rend获取第一个字符的位置

cpp 复制代码
string str("hello")
for (auto it = str.rbegin(); it != str.rend(); ++it) {
    cout << *it;//从右往左访问->olleh
}
cpp 复制代码
str.push_back('!');     // 尾部添加字符

5. string的修改操作

函数名称 功能说明

push_back 在字符串后尾插字符c

cpp 复制代码
str.push_back('!');     // 尾部添加字符

append 在字符串后追加一个字符串

cpp 复制代码
str.append(" world");   // 追加字符串

operator+= (重点) 在字符串后追加字符串str

cpp 复制代码
str += "!!!";           // 最常用的追加方式

c_str(重点) 返回C格式字符串

find(重点) 从字符串pos位置开始往找字符c/字符串,返回该字符在字符串中的位置

cpp 复制代码
size_t pos = str.find("world");    // 查找子串

rfind (重点) 从字符串pos位置开始往找字符c/字符串,返回该字符在字符串中的位置

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

cpp 复制代码
if (pos != string::npos) {
    string sub = str.substr(pos, 5); // 截取子串
}

erase 删除子串

cpp 复制代码
str.erase(5, 4);// 删除子串(从起始地点为5的位置开始删除4个字符)

6. string类的模拟实现

6.1 浅拷贝问题

浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致 多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉

cpp 复制代码
class String {
private:
    char* _str;
public:
    String(const char* str = "") {
        _str = new char[strlen(str) + 1];
        strcpy(_str, str);
    }
    
    // 问题:默认拷贝构造是浅拷贝!
    ~String() { delete[] _str; }
};

void Test() {
    String s1("hello");
    String s2(s1);  // 浅拷贝!s1和s2指向同一内存
} // 析构时同一内存被释放两次,程序崩溃

6.2 深拷贝解决方案

如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给 出。一般情况都是按照深拷贝方式提供。

cpp 复制代码
class String {
public:
    String(const char* str = "") {
        _str = new char[strlen(str) + 1];
        strcpy(_str, str);
    }
    
    // 深拷贝构造
    String(const String& s) {
        _str = new char[strlen(s._str) + 1];
        strcpy(_str, s._str);
    }
    
    // 深拷贝赋值
    String& operator=(const String& s) {
        if (this != &s) {
            char* temp = new char[strlen(s._str) + 1];
            strcpy(temp, s._str);
            delete[] _str;
            _str = temp;
        }
        return *this;
    }
    
    ~String() { delete[] _str; }
    
private:
    char* _str;
};

现代写法(推荐)

cpp 复制代码
class String {
public:
    String(const char* str = "") {
        _str = new char[strlen(str) + 1];
        strcpy(_str, str);
    }
    
    // 拷贝构造:利用临时对象和swap
    String(const String& s) : _str(nullptr) {
        String temp(s._str);
        swap(_str, temp._str);
    }
    
    // 赋值:参数为值传递,利用swap
    String& operator=(String s) {
        swap(_str, s._str);
        return *this;
    }
    
    ~String() { delete[] _str; }
    
private:
    char* _str;
};

结语

string类是C++中极其重要的组件,它让我们能够更加安全、高效地处理字符串。通过本文的学习,希望大家能够:

  1. 熟练掌握string类的各种常用接口

  2. 理解深拷贝和浅拷贝的区别及重要性

  3. 能够自己实现一个简单的string

  4. 在实战中灵活运用string解决各种字符串问题

练习建议:

  • 实现自己的String类(包含基本操作)

  • 完成leetcode上的字符串相关题目

  • 阅读标准库中string的源码实现

相关推荐
我命由我123455 小时前
Photoshop - Photoshop 工具栏(10)透视裁剪工具
经验分享·笔记·学习·ui·职场和发展·职场发展·photoshop
Madison-No75 小时前
【C++】探秘string的底层实现
开发语言·c++
sensen_kiss6 小时前
INT301 Bio-computation 生物计算(神经网络)Pt.1 导论与Hebb学习规则
人工智能·神经网络·学习
koko426 小时前
天津小公司面经
java·学习·面试
无限进步_6 小时前
C语言字符串与内存操作函数完全指南
c语言·c++·算法
闻缺陷则喜何志丹6 小时前
【C++贪心】P10537 [APIO2024] 九月|普及+
c++·算法·贪心·洛谷
QiZhang | UESTC6 小时前
JAVA算法练习题day27
java·开发语言·c++·算法·leetcode·hot100
坚持就完事了6 小时前
2-C语言中的数据类型
c语言·开发语言
Stanford_11067 小时前
关于嵌入式硬件需要了解的基础知识
开发语言·c++·嵌入式硬件·微信小程序·微信公众平台·twitter·微信开放平台