【C++】string类

目录

前言

string常用方法

1.构造函数

2.对 string 对象赋值

3. string字符串转换为C风格的字符串

4.string 字符串的输入输出

5.string类对象容量操作

① size()/length() 

② capacity/reserve/resize

6.遍历访问字符串中的字符 

① for + operartor[]

② 迭代器

③ 范围for(c++11新加) 

7.string对象的修改操作

(1)插入操作

 ① 尾部插入或追加字符串。

② 指定位置插入字符串 insert()

(2)删除操作

① 删除尾部字符 pop_back()

② 删除字符串 erase()

(3)string对象的比较

方法一:比较运算符

方法二: compare() 成员函数

(4)求 string 对象的子串 【substr()成员函数】

(5)交换两个string对象的内容【swap()函数】

(6)查找子串和字符【find()函数】

  (7) 替换子串【replace()成员函数】


前言

C++大大增强了对字符串的支持,除了可以使用C风格的字符串,还可以使用内置的 string 类。string 类处理起字符串来会方便很多,完全可以代替C语言中的字符数组或字符串指针。string 是 C++ 中常用的一个类,它非常重要。使用 string 类需要包含头文件<string>。


string常用方法

1.构造函数

构造函数原型功能说明
string()构造空的string类对象,即空字符串
string(const char* s)用c-string s来构造一个string类对象
string(const string& s)拷贝构造函数,通过拷贝构造string 类对象
string(size_t n,char c)构造一个包含n个字符c的string类对象

string 类有多个构造函数,用法示例如下:

string s1();            // s1 = ""(变量 s1 只是定义但没有初始化,编译器会将默认值赋给 s1,默认值是“”,即为空字符串

string s2("Hello");          // s2 = "Hello"(变量 s2 在定义的同时被初始化为“Hello”,与C风格的字符串不同,string 的结尾没有结束标志‘\0’

string s3(4, 'K');         // s3 = "KKKK"(变量 s3 被初始化为由 4个'K'符组成的字符串"KKKK")

string s4("12345", 1, 3);       //s4 = "234",即 "12345" 的从下标 1 开始,长度为 3 的子串

string 类没有接收一个整型参数或一个字符型参数的构造函数。下面的两种写法是错误的:

string s1('K');//(错误)

string s2(123);//(错误)

 

2.对 string 对象赋值

可以用 char* 类型的变量、常量,以及 char 类型的变量、常量对 string 对象进行赋值。例如:

string s1;

s1 = "Hello"; // s1 = "Hello"

s2 = 'K'; // s2 = "K”

string 类还有 assign 成员函数,可以用来对 string 对象赋值。assign 成员函数返回对象自身的引用。

assign原型:

例如:

string s1("12345"), s2;

s3.assign(s1);         // s3 = s1,string类对象拷贝

s2.assign(s1, 1, 2);         // s2 = "23",即 s1 的子串(1, 2),取子串

s2.assign("abcde", 2, 3);        // s2 = "cde",即 "abcde" 的子串(2, 3)

assign的官方介绍:

https://cplusplus.com/reference/string/string/assign/ 

 

3. string字符串转换为C风格的字符串

虽然 C++ 提供了 string 类来替代C语言中的字符串,但是在实际编程中,有时候必须要使用C风格的字符串(例如打开文件时的路径),为此,string 类为我们提供了一个转换函数 c_str(),该函数能够将 string 字符串转换为C风格的字符串,并返回该字符串的 const 指针(const char*)。请看下面的代码:

string path = "D:\\demo.txt";

FILE *fp = fopen(path.c_str(), "rt");          //为了使用C语言中的 fopen() 函数打开文件,必须将 string 字符串转换为C风格的字符串。

 

4.string 字符串的输入输出

string 类重载了输入输出运算符,可以像对待普通变量那样对待 string 变量,也就是>>进行输入,用<<进行输出。请看下面的代码:

#include <iostream>

#include <string>

using namespace std;

int main(){

     string s;

     cin>>s; //输入字符串

     cout<<s<<endl; //输出字符串

     return 0;

}

运行结果:
http://c.biancheng.net  http://vip.biancheng.net
http://c.biancheng.net
【注意】虽然我们输入了两个由空格隔开的网址,但是只输出了一个,这是因为输入运算符>>默认会忽略空格,遇到空格就认为输入结束,所以最后输入的http://vip.biancheng.net没有被存储到变量 s。

 

5.string类对象容量操作

函数名称功能说明
size()/length()返回字符串有效字符长度
capacity()返回对象总空间大小
reserve(size_t n)为字符串对象预留n字节空间
resize(size_t n,char c) 将有效字符串长度改为n,多出的位置用字符c填充(缺省默认使用‘\0’填充)
① size()/length() 

string字符串求字符串长度时,可以调用 string 类提供的 length() 或size()成员函数

string s = "http://c.biancheng.net";

int len1 = s.length();

int len2=s.size();

cout<<len1<< " "<<len2<<endl;

输出结果为22 22。由于 string 的末尾没有'\0'字符,所以 length() 返回的是字符串的真实长度,而不是长度 +1,size()也是返回字符串中字符的实际个数

注意:size()和length()底层实现原理完全相同,引入size()的原因是为了与其他容器接口保持一致,一般情况下都用size()

② capacity/reserve/resize
#include <iostream>
#include <string>
using namespace std;

void stringTest1()
{
    string s("Hello World");
    
    cout<<s.size()<<endl;      // 11
    cout<<s.length()<<endl;    // 11
    cout<<s.capacity()<<endl;  // 15
    cout<<s<<endl;             //"Hello World"
    
    s.clear();                //将s中的字符串清空
    cout<<s.size()<<endl;     // 0
    cout<<s.capacity()<<endl; // 15
    //所以clear只是改变s的有效字符串长度size,s的容量(底层空间)并没有改变
    
    s.resize(10,'a');
    cout<<s.size()<<endl;      // 10
    cout<<s.capacity()<<endl;  // 15
    cout<<s<<endl;             //"aaaaaaaaaa"
    
    s.resize(20);
    cout<<s.size()<<endl;      // 20
    cout<<s.capacity()<<endl;  // 30
    cout<<s<<endl;             //"aaaaaaaaaa"这里其实后面有10个'\0'作为填充
    
    s.resize(5);
    cout<<s.size()<<endl;      // 5
    cout<<s.capacity()<<endl;  // 30
    cout<<s<<endl;             //"aaaaa"
    //所以resize改变的是有效字符串的个数
    //当n值增大时,可能会改变底容量大小,即底层空间增加
    //而n值减少,则容量不变。
}

int main()
{
    
    stringTest1();
    return 0;
}
#include <iostream>
#include <string>
using namespace std;

void stringTest2()
{
    string s; 
    s.reserve(100); 
    cout << s.size() << endl;     //0
    cout << s.capacity() << endl; //100

    s.reserve(50); 
    cout << s.size() << endl;     // 0
    cout << s.capacity() << endl; //100
}

小结:

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

b.resize将字符串有效字符个数改变为n个,个数增多时,多余空间进行填充。

另外,resize将元素增多时,可能会改变底层容量的大小,而元素减少时,底层容量不变。

c.reserve为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserve不会改变容量大小。

 

6.遍历访问字符串中的字符 

① for + operartor[]

string 字符串也可以像C风格的字符串一样按照下标来访问其中的每一个字符。string 字符串的起始下标仍是从 0 开始。请看下面的代码:

#include <iostream>
#include <string>
using namespace std;

int main()
{
   string s = "1234567890";
   for(int i=0,len=s.length(); i<len; i++)
   {
        cout<<s[i]<<" ";

   }
   cout<<endl;

   s[5] = '5';
   cout<<s<<endl;

   return 0;

}

运行结果:
1 2 3 4 5 6 7 8 9 0
1234557890
本例定义了一个 string 变量 s,并赋值 "1234567890",之后用 for 循环遍历输出每一个字符。借助下标,除了能够访问每个字符,也可以修改每个字符s[5] = '5';就将第6个字符修改为 '5',所以 s 最后为 "1234557890"。

② 迭代器
void stringTest3()
{
    string s("hello world");
    
    for(string::iterator it=s.begin();it!=s.end();it++)//正向迭代器
    {
        cout<<*it;
    }
    cout<<endl;
    
    for(string::reverse_iterator rit=s.rend();rit>=s.rbegin();rit--)//反向迭代器
    {
        cout<<*rit;
    }
    cout<<endl;
}
③ 范围for(c++11新加) 
void stringTest4()
{
    string s("hello world");
    
    for(auto it:s)//通过auto自动推导
    {
        cout<<it<<endl;
    }
}

遍历容器时,按auto自动推导的类型是容器的value_type类型,而不是迭代器,所以这边的it其实是字符类型,输出时不用解引用。

7.string对象的修改操作

(1)插入操作
 ① 尾部插入或追加字符串。

方法一:push_back()

push_back的作用是在string尾部插入一个字符。注意是一个字符,而不是字符串。

函数原型:

 示例如下:

void stringTest4()
{
    string s("hello world");
    s.push_back('!'); //尾部插入字符!
    cout<<s<<endl;    //“hello world!”
}

方法二:+ 运算符

string 类可以使用  += 运算符来直接拼接字符串,再也不需要使用C语言中的 strcat()、strcpy()、malloc() 等函数来拼接字符串了,再也不用担心空间不够会溢出了。
用 + 来拼接字符串时,运算符的两边可以都是 string 字符串,也可以是一个 string 字符串和一个C风格的字符串,还可以是一个 string 字符串和一个字符数组,或者是一个 string 字符串和一个单独的字符。请看下面的例子:

#include <iostream>
#include <string>
using namespace std;

int main(){
    string s1 = "first ";
    string s2 = "second ";
    char *s3 = "third ";
    char s4[] = "fourth ";
    char ch = '@';

    string s5 = s1 + s2;
    string s6 = s1 + s3;
    string s7 = s1 + s4;
    string s8 = s1 + ch;

    cout<<s5<<endl<<s6<<endl<<s7<<endl<<s8<<endl;

    return 0;

}

运行结果:
first second
first third
first fourth
first @

方法三:append()

 string 类还有 append 成员函数,可以用来向字符串后面添加内容。append 成员函数返回对象自身的引用。

函数原型:

示例如下: 

string s1("123"), s2("abc");
s1.append(s2);  // s1 = "123abc"
s1.append(s2, 1, 2);  // s1 = "123abcbc"
s1.append(3, 'K');  // s1 = "123abcbcKKK"
s1.append("ABCDE", 2, 3);  // s1 = "123abcbcKKKCDE",添加 "ABCDE" 的子串(2, 3)
② 指定位置插入字符串 insert()

作用: string 字符串中指定的位置插入另一个字符串(它可以是 string 字符串,也可以是C风格的字符串),返回值为对象自身的引用。

函数原型:


示例如下:

string s1("Limitless"), s2("00");

s1.insert(2, "123"); //在下标 2 处插入字符串"123",s1 = "Li123mitless"

s1.insert(3, s2); //在下标 2 处插入 s2 , s1 = "Li10023mitless"

s1.insert(3, 5, 'X'); //在下标 3 处插入 5 个 'X',s1 = "Li1XXXXX0023mitless"

insert() 函数的第一个参数有越界的可能,如果越界,则会产生运行时异常。

(2)删除操作
① 删除尾部字符 pop_back()

示例如下:

// string::pop_back
#include <iostream>
#include <string>

int main ()
{
  std::string str ("hello world!");
  str.pop_back(); //删除尾部字符!
  std::cout << str << std::endl; //"hello world"
  return 0; 
}
② 删除字符串 erase()

erase() 函数可以删除 string 中的一个子字符串

函数原型:

pos:要删除的子字符串的起始下标

len: 要删除子字符串的长度。如果不指明 len 的话,那么直接删除从 pos 到字符串结束处的所有字符(此时 len = str.length() - pos)。

示例如下:

   string s1("Real Steel");

  s1.erase(1, 3); //删除子串(1, 3),此后 s1 = "R Steel"

  s1.erase(5); //删除下标5及其后面的所有字符,此后 s1 = "R Ste"

  std::string str ("This is an example sentence.");
  std::cout << str << '\n'; // "This is an example sentence."
                                           
  str.erase (10,8);                     
  std::cout << str << '\n';  // "This is an sentence."
                                          
  str.erase (str.begin()+9);   // "This is a sentence."             
                                          
  str.erase (str.begin()+5, str.end()-9);  // "This sentence."
  std::cout << str << '\n';

 【注意】可能有人认为,在 pos 参数没有越界的情况下, len 参数也可能会导致要删除的子字符串越界。但实际上这种情况不会发生,erase() 函数会从len和str.length() - pos两个值中取出最小的一个作为待删除子字符串的长度。

(3)string对象的比较
方法一:比较运算符

用 <、<=、==、!=、>=、> 运算符比较 string 对象

方法二: compare() 成员函数

string 类还有 compare 成员函数,可用于比较字符串。

compare 成员函数有以下返回值:

  • 小于 0 表示当前的字符串小;
  • 等于 0 表示两个字符串相等;
  • 大于 0 表示另一个字符串小。
string s1("hello"), s2("hello, world");
int n = s1.compare(s2);
n = s1.compare(1, 2, s2, 0, 3);  //比较s1的子串 (1,2) 和s2的子串 (0,3)
n = s1.compare(0, 2, s2);  // 比较s1的子串 (0,2) 和 s2
n = s1.compare("Hello");
n = s1.compare(1, 2, "Hello");  //比较 s1 的子串(1,2)和"Hello”
n = s1.compare(1, 2, "Hello", 1, 2);  //比较 s1 的子串(1,2)和 "Hello" 的子串(1,2)
(4)求 string 对象的子串 【substr()成员函数

substr 成员函数可以用于求pos开始,长度为len的子串。

原型如下:

调用时,如果省略len或len超过了字符串的长度,则子串就是从pos开始直到字符串结束的部分。

示例如下:

string s1 = "this is ok";

string s2 = s1.substr(2, 4); // s2 = "is i"

s2 = s1.substr(2); // s2 = "is is ok"

【注意】系统对 substr() 参数的处理和 erase() 类似:

  • 如果 pos 越界,会抛出异常;
  • 如果 len 越界,会提取从 pos 到字符串结尾处的所有字符。
(5)交换两个string对象的内容【swap()函数

swap 成员函数可以交换两个 string 对象的内容。例如:

string s1("West”), s2("East");

s1.swap(s2); // s1 = "East",s2 = "West"

(6)查找子串和字符【find()函数】

string 类有一些查找子串和字符的成员函数,它们的返回值都是子串或字符在 string 对象字符串中的位置(即下标)。如果查不到,则返回 string::npos。string: :npos 是在 string 类中定义的一个静态常量。这些函数如下:

  • find:从前往后查找子串或字符出现的位置。
  • rfind:从后往前查找子串或字符出现的位置。
  • find_first_of:从前往后查找何处出现另一个字符串中包含的字符。例如:
  • s1.find_first_of("abc");  //查找s1中第一次出现"abc"中任一字符的位置
  • find_last_of:从后往前查找何处出现另一个字符串中包含的字符。
  • find_first_not_of:从前往后查找何处出现另一个字符串中没有包含的字符。
  • find_last_not_of:从后往前查找何处出现另一个字符串中没有包含的字符。

示例如下:

#include <iostream>
#include <string>
using namespace std;

int main()
{
    string s1("Source Code");
    int n;
    if ((n = s1.find('u')) != string::npos) //查找 u 出现的位置
        cout << "1) " << n << "," << s1.substr(n) << endl;//输出 l)2,urce Code
    
    if ((n = s1.find("Source", 3)) == string::npos)//从下标3开始查找"Source",找不到
        cout << "2) " << "Not Found" << endl; //输出 2) Not Found
    
    if ((n = s1.find("Co")) != string::npos)//查找子串"Co"。能找到,返回"Co"的位置
        cout << "3) " << n << ", " << s1.substr(n) << endl;//输出 3) 7, Code
    
    if ((n = s1.find_first_of("ceo")) != string::npos)//查找第一次出现或 'c'、'e'或'o'的位置
        cout << "4) " << n << ", " << s1.substr(n) << endl;//输出 4) l, ource Code
    
    if ((n = s1.find_last_of('e')) != string::npos)//查找最后一个 'e' 的位置
        cout << "5) " << n << ", " << s1.substr(n) << endl; //输出 5) 10, e

    if ((n = s1.find_first_not_of("eou", 1)) != string::npos)
        //从下标1开始查找第一次出现非 'e'、'o' 或 'u' 字符的位置
        cout << "6) " << n << ", " << s1.substr(n) << endl; //输出 6) 3, rce Code
   
    return 0;
}
(7) 替换子串【replace()成员函数

replace 成员函数可以对 string 对象中的子串进行替换,返回值为对象自身的引用

示例如下:

string s1("Real Steel");

s1.replace(1, 3, "123456", 2, 4); //用 "123456" 的子串(2,4) 替换 s1 的子串(1,3)

cout << s1 << endl; //输出 R3456 Steel

string s2("Harry Potter");

s2.replace(2, 3, 5, '0'); //用 5 个 '0' 替换子串(2,3)

cout << s2 << endl; //输出 HaOOOOO Potter

int n = s2.find("OOOOO"); //查找子串 "00000" 的位置,n=2

s2.replace(n, 5, "XXX"); //将子串(n,5)替换为"XXX"

cout << s2 < < endl; //输出 HaXXX Potter
  • 5
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值