当前位置:   article > 正文

C++string类的常用方法_c++ string类的常用方法

c++ string类的常用方法

前言

string是C++风格的字符串,本质上是一个类,它的内部封装了char *,是一个char *型的容器

使用string需要包含<string>头文件

string的内部封装了很多方法,本文将重点介绍string的一些常用方法,这些方法足以应对日常的刷题和比赛

1. string的构造方法

1.1 无参构造

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str;
    cout << "str = " << str << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

1.2 字符数组构造

#include <iostream>
#include <string>

using namespace std;

int main() {
    char words[15] = {"Hello World"};
    string str(words);
    cout << "str = " << str << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2. string的赋值

string类重载了赋值符号

string的赋值本质上是将数据源的内容拷贝一份放到string里,修改string的值并不会影响数据源

2.1 数据源为字符数组

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str;
    char words[15] = {"Hello"};
    str = words;
    cout << "str = " << str << endl;
    
    str[0] = 'h';
    cout << "str = " << str << endl;
    cout << "words = " << words << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

输出结果为

str = Hello
str = hello
words = Hello
  • 1
  • 2
  • 3

2.2 数据源为string

#include <iostream>
#include <string>

using namespace std;

int main() {
    string src = "Hello World";
    string destination;
    destination = src;
    cout << "destination = " << destination << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2.3 构造方法和赋值中的细节

先看以下代码

#include <iostream>
#include <string>

using namespace std;

int main() {
    string src = "Hello World";
    string destination = src;
    cout << "destination = " << destination << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

虽然代码string destination = src;看起来是src为destination赋值,但是经过编译器优化后,该句代码等价于string destination(src);,也就是说,该句代码本质上是调用了string类的构造方法,而不是赋值操作

我们可以使用自定义的类来验证

#include <iostream>

using namespace std;

class Student {
public:
    int age;
    double height;

public:
    Student() {
        this->age = 0;
        this->height = 0.0;
    }

    Student(const Student &anotherStudent) {
        cout << "拷贝构造函数" << endl;
        this->age = anotherStudent.age;
        this->height = anotherStudent.height;
    }

    Student &operator=(const Student &anotherStudent) {
        cout << "重载赋值符号" << endl;
        this->age = anotherStudent.age;
        this->height = anotherStudent.height;
        return *this;
    }
};

int main() {
    Student tom;
    tom.age = 18;
    tom.height = 180;

    Student jerry = tom;
    cout << "jerry.age = " << jerry.age << endl;
    cout << "jerry.height = " << jerry.height << endl;

    Student amy;
    amy = tom;
    cout << "amy.age = " << amy.age << endl;
    cout << "amy.height = " << amy.height << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

输出结果为

拷贝构造函数
jerry.age = 18
jerry.height = 180
重载赋值符号
amy.age = 18
amy.height = 180
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3. string的存取

string类重载了[]符号

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str = "Hello,World";
    cout << "str[0] = " << str[0] << endl;
    str[0] = 'h';
    cout << "str[0] = " << str[0] << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

4. string的拼接

string类重载了+和+=符号,可以接收字符数组、字符、string、字符串等类型的变量

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str01;
    char words[15] = {"Hello"};
    str01 += words;
    cout << "str01 = " << str01 << endl;

    char ch = ',';
    str01 += ch;
    cout << "str01 = " << str01 << endl;

    string temp = "World";
    str01 += temp;
    cout << "str01 = " << str01 << endl;

    str01 += "!";
    cout << "str01 = " << str01 << endl;

    string str02;
    str02 = str02 + words + ch + temp + "!";
    cout << "str02 = " << str02 << endl;

    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

输出结果为

str01 = Hello
str01 = Hello,
str01 = Hello,World
str01 = Hello,World!
str02 = Hello,World!
  • 1
  • 2
  • 3
  • 4
  • 5

5. string的查找

5.1 find方法

string类的find方法有多个重载版本,我们只学习它的基本用法

find方法可以接收string、字符、字符数组三种类型的参数

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str = "Hello,World Hello,World! Hello,World!";
    
    string temp = "Hello";
    char ch = ',';
    char words[15] = "World";
    
    int index = str.find(temp);
    cout << "index = " << index << endl;

    index = str.find(ch);
    cout << "index = " << index << endl;

    index = str.find(words);
    cout << "index = " << index << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

输出结果为

index = 0
index = 5
index = 6
  • 1
  • 2
  • 3

上述的find方法只接收一个参数,默认是从下标0开始寻找子串

如果我们想从特定的位置开始寻找子串,我们可以填入开始寻找的下标作为find方法的第二个参数

配合循环,我们就可以在母串中找到所有子串的开始位置

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str = "Hello,World Hello,World! Hello,World!";
    int start = 0;

    while (true) {
        int index = str.find("Hello", start);
        if (index == -1) {
            break;
        }
        cout << "index = " << index << endl;
        start = index + 5;
    }

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

输出结果为

index = 0
index = 12
index = 25
  • 1
  • 2
  • 3

5.2 string::npos

当使用string类的find方法查找不到子串时,find方法将会返回string::npos

string::npos的类型本质上是unsigned long long,而且string::nops的数位(二进制)都是1,也就是说string::npos的值为264-1,即18,446,744,073,709,551,615

当我们用int、long、long long等有符号整形变量去接收string::npos时,该有符号整形变量的数位(二进制)将全变成1,而-1的补码也全部为1,所以该有符号整形变量的值也就变成了-1

因此我们可以根据find方法是否返回-1或string::npos来判断是否寻找到子串

#include <iostream>
#include <string>

using namespace std;

int main() {
    cout << "string::npos = " << string::npos << endl;

    string str = "Hello,World";
    if (-1 == str.find("Tom")) {
        cout << "Can not find subStr Tom" << endl;
    }

    if (string::npos == str.find("Jerry")) {
        cout << "Can not find subStr Jerry" << endl;
    }

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

输出结果为

string::npos = 18446744073709551615
Can not find subStr Tom
Can not find subStr Jerry
  • 1
  • 2
  • 3

5.2 find方法的底层

find方法的底层并没有采用KMP算法等更高效的字符串匹配算法

find方法使用的是朴素的线性搜索算法,也就是逐个字符比对,时间复杂度大约为 O(n*m) ,其中 n 为母串长度,m 为子串长度。

6. string的替换

string的替换主要是使用replace方法,replace方法也有很多个重载版本,我们只学习它的基本用法

常规的replace方法接收三个参数

  • 第一个参数为替换的起始下标
  • 第二个参数为替换的长度
  • 第三个参数为新的字符串,该字符串可以是string类,也可以是字符数组
#include <iostream>
#include <string>

using namespace std;

int main() {
    string str = "Hello,World";
    string str01 = "hello";
    char str02[15] = "world";

    str.replace(0, str01.length(), str01);
    cout << "str = " << str << endl;

    str.replace(6, 5, str02);
    cout << "str = " << str << endl;
    
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

输出结果

str = hello,World
str = hello,world
  • 1
  • 2

7. string的比较

string类重载了>=、<=、>、<、!=、==符号,使得string类在进行字符串比较时可以接收char数组类型或string类型的参数

string类的比较是将两个字符串的字符从左到右逐个比较(比较的依据是字符的ASCII码值),直到两个字符串出现不同的字符或者两个字符串中的每个字符都比较完之后返回

string类在进行字符串的比较时会返回三个值

  • -1,第一个字符串小于第二个字符串
  • 0,第一个字符串等于第二个字符串
  • 1,第一个字符串大于第二个字符串
#include <iostream>
#include <string>

using namespace std;

int main() {
    string str01 = "Hello,World";
    string str02 = "hello,World";
    char str03[20] = "Hello,world";

    cout << (str01 == str02) << endl;
    cout << (str01 > str03) << endl;
    cout << (str02 > str03) << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

输出结果

0
0
1
  • 1
  • 2
  • 3

8. string的长度

使用string类的length方法或size方法可以得到string的长度

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str = "Hello,World";
    cout << "str.length() = " << str.length() << endl;
    cout << "str.size() = " << str.size() << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

输出结果

str.length() = 11
str.size() = 11
  • 1
  • 2

9. string的插入

string的插入使用的是insert方法,insert方法也有很多个重载版本,我们只学习它的基本用法

常规的insert方法接收两个参数

  • 第一个参数为插入的起始位置
  • 第二个参数为要插入的字符串,类型可以是char数组或string
#include <iostream>
#include <string>

using namespace std;

int main() {
    string str = "Hello";
    str.insert(5, "World");
    cout << str << endl;
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

输出结果为

HelloWorld
  • 1

10. string的删除

string的插入使用的是erase方法,该方法主要有两个版本

第一个版本接收两个参数

  • 第一个参数为起始坐标
  • 第二个参数为要删除的长度

第二个版本只接收一个参数,该参数为起始坐标,使用该版本将会清空起始位置及之后的所有字符

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str01 = "HelloWorld!";
    str01.erase(5, 5);
    cout << str01 << endl;

    string str02 = "HelloWorld!";
    str02.erase(5);
    cout << str02 << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

输出结果为

Hello!
Hello
  • 1
  • 2

11. string的子串获取

string的子串获取主要使用substr方法,该方法接收两个参数

  • 第一个参数为起始的位置
  • 第二个参数为截取的长度

如果省略第二个参数,将会截取从起始位置开始到字符串结尾的整个子串

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str = "HelloWorld!";
    cout << "str.substr(5, 5) = " << str.substr(5, 5) << endl;
    cout << "str.substr(5) = " << str.substr(5) << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

输出结果为

str.substr(5, 5) = World
str.substr(5) = World!
  • 1
  • 2

12. string与基本数据类型之间的转换

注意:以下介绍的string与基本数据类型之间相互转换的方法是在C++11之后才出现的,在C++11之前的版本中使用以下方法程序将会报错

12.1 基本数据类型转string

基本数据类型转string使用的是to_string方法

#include <iostream>
#include <string>

using namespace std;

int main() {
    int number = 8848;
    long long date = 20202020;
    double pi = 3.1415926;

    string NUMBER = to_string(number);
    string DATE = to_string(date);
    string PI = to_string(pi);

    cout << "NUMBER = " << NUMBER << endl;
    cout << "DATE = " << DATE << endl;
    cout << "PI = " << PI << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

输出结果为

NUMBER = 8848
DATE = 20202020
PI = 3.141593
  • 1
  • 2
  • 3

12.2 string转基本数据类型

这里主要介绍string转换成int、long long、double,string,转成其它基本数据类型的方法可以类比

  • stoi方法(string to int),将string转为int
  • stoll方法(string to long long),将string转为long long
  • stod方法(string to double),将string转为double
#include <iostream>
#include <string>

using namespace std;

int main() {
    string intStr = "8848";
    string timeStr = "202002202020";
    string piStr = "3.1415926";

    cout << "stoi(intStr) = " << stoi(intStr) << endl;
    cout << "stoll(timeStr) = " << stoll(timeStr) << endl;
    cout << "stod(piStr) = " << stod(piStr) << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

输出结果为

stoi(intStr) = 8848
stoll(timeStr) = 202002202020
stod(piStr) = 3.14159
  • 1
  • 2
  • 3

12.3 知识点补充——浮点数的格式化输出

当浮点数的总长度大于等于7(包括小数点)时,C/C++程序输出浮点数的格式会千奇百怪,下面介绍两种格式化输出浮点数的方法

12.3.1 C++风格

我们可以借助<iomanip>头文件来控制浮点数的输出格式

  • setw:总长度
  • setfill:浮点数的位数不够时自动填充的字符
  • setprecision:保留的精度
  • fixed:修饰符,配合setprecision使用,表示以固定小数位输出,如果不加这个修饰符,浮点数可能会以科学计数法的形式输出
  • setiosflags:设置对齐方向,默认为右对齐
#include <iostream>
#include <string>
#include <iomanip>

using namespace std;

int main() {
    string piStr = "3.1415926";

    double pi = stod(piStr);
    cout << "************" << endl; // 12个*
    cout << setw(12) << setfill('\0') << setprecision(8) << fixed << setiosflags(ios::left) << pi << endl;
    cout << setw(12) << setfill('\0') << setprecision(8) << fixed << setiosflags(ios::right) << pi << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

输出结果为

************
3.14159260
  3.14159260
  • 1
  • 2
  • 3

12.3.2 C风格

可以使用C语言的printf来控制浮点数的输出格式

  • 格式为%width.precisionlf
  • width为输出的浮点数的总宽度,包括小数点,当浮点数的宽度小于width时,会自动填充'\0'字符(width参数可以省略)
  • precision为保留的小数位数
  • 浮点数的小数位数小于precision时会自动在浮点数后面补0
  • 如果width小于等于precision,width参数将不起作用
#include <cstdio>

using namespace std;

int main() {
    double pi = 3.1415926;

    printf("************\n");
    printf("%12.8lf\n", pi); // 默认是右对齐
    printf("%-12.8lf\n", pi); // 左对齐
    printf("%.8lf\n", pi); // 省略width
    printf("%6.8lf\n", pi); // precision >= width

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

输出结果为

************
  3.14159260
3.14159260
3.14159260
3.14159260
  • 1
  • 2
  • 3
  • 4
  • 5

13. string转C风格的字符串

string类的c_str()方法返回一个指向以'\0'结尾的字符数组的指针,该字符数组包含了与string对象相同的字符序列。

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str = "Hello, World!";
    
    const char *cstr = str.c_str();
    cout << cstr << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注意,c_str()方法返回的C风格字符串指针指向的内存是由string对象管理的,因此在string对象的生命周期内,该C风格字符串是有效的。
如果string对象被销毁或修改,那么之前返回的C风格字符串指针将不再有效。

先看以下代码

#include <iostream>
#include <string>

using namespace std;

const char *cstr;

void function() {
    string str = "Hello,World!";
    cstr = str.c_str();
}

int main() {
    function();

    cout << cstr << endl;
    cout << cstr << endl;
    cout << cstr << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

以上代码在function()函数中创建了一个局部的string对象str,并将c_str()方法返回的指针赋值给全局变量cstr。

然而,当function()函数结束时,局部变量str将被销毁,这意味着cstr现在指向的内存区域已经不再有效。

因此,当在main()函数中试图通过cout输出cstr时,程序正在访问已经被释放的内存,这是未定义的行为,可能会导致程序崩溃或输出不可预测的结果。

当然,如果你拷贝上述代码到自己电脑上运行,大概率是没有问题的。

以下是GPT4.0给出的分析和改进后的代码

  • 虽然你的代码在运行时没有报错,但这并不意味着代码是正确的。

  • 你的代码中存在未定义行为,这意味着程序可能会以任何方式运行,包括看似“正常”运行。

  • 在你的例子中,尽管str已经被销毁,但其内存可能尚未被操作系统回收或重新分配给其他对象,因此你可能仍然能够看到原来的内容。

  • 然而,这是非常不安全的,因为你无法预测何时这块内存会被重新分配。

  • 因此,你应该避免这种未定义行为,确保你的代码总是安全、可预测的。

#include <iostream>
#include <string>

using namespace std;

string function() {
    string str = "Hello, World!";
    return str;
}

int main() {
    string str = function();

    const char *cstr = str.c_str();

    std::cout << cstr << std::endl;
    std::cout << cstr << std::endl;
    std::cout << cstr << std::endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号