C++中的string

本文详细介绍了C++中字符串的基本操作、运算符重载、字符串处理方法,包括字符串的访问、长度获取、容量查看、大小调整、赋值、追加、插入、替换、删除、比较等,以及字符串与字符数组之间的转换,提供了丰富的实例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明:以下笔记大部分来自文末的Reference,并结合自己的理解整理成笔记

1. 基本操作

1.1 头文件
#include <string>
1.2 声明与初始化
string s0("Initial string");

// constructors used in the same order as described above:
string s1;						// 默认初始化,s1为一个空字符串
string s2(s0);					// s2是s0的副本
string s2 = s0;					// 与上面是等价的
string s3(s0, 8, 3);			// 将s0,从下标8开始,拷贝3个字符至s3
string s4("A character sequence");	// s4字符串的副本,处理字面值最后的那个空字符串外
string s4 = "A character sequence"; // 与上面是等价的
string s5("Another character sequence", 12);// 从字符串下标12开始,直到字符串结尾进行拷贝
string s6a(10, 'x');			// 把s6a初始化为10个字符'x'组成的串
string s6b(10, 42);				// 把s6a初始化为10个'*'组成的串,42ASCII码为'*'
string s7(s0.begin(), s0.begin() + 7); // 从s0第一个个迭代器开始拷贝,直到s0.begin() + 7个迭代器
char cs[] = "12345";
string s8(cs, 3);				// 复制字符串cs的前3个字符串到s当中

2. 运算符重载

+ 和 +=连接字符串
=字符串赋值
>、>=、< 和 <=字符串比大小(例如a < b, aa < ab)
==、!=字符串是否相等
cin << s、cout >> s字符串输入输出,不能读入空格,以空格、制表符、回车符为结束标志
getline(cin, s)字符串输入输出,可以读入空格和制表符,以回车符作为结束标志

注意:使用重载的运算符 + 时,必须保证前两个操作数至少有一个为 string 类型。例如,下面的写法是不合法的:

#include <iostream>
#include <string>
int main() {
    string str1 = "cat";
    cout << "apple" + "boy" + str1; // 不合法
    string str2 = str1 + "apple";   // 合法
    return 0;
}

3. 字符串处理

3.1 使用下标访问元素 []
cout << str[0] << endl;  
3.2 使用 at() 方法访问
cout << str.at(0) << endl;  // (如果溢出会抛出异常)
3.3 size() 获取字符串长度
string str = "12345";
str.size();		// 长度为5
3.4 length() 获取字符串长度
string str = "12345";
str.length();		// 长度为5
3.5 capacity() 获取字符串容量
string str = "12345";
str.capacity();		// 字符串容量为5
3.6 resize() 更改字符串大小

这里改变的是 size() 大小,即string中字符数量。
(1)若新的大小n比原来的 size() 小,则多于n的部分直接删除。
(2)若新的大小n大于string中当前元素数量,则会在string当前的尾部掺入适量元素,是的vector的大小变为n。如果,为 resize() 方法指定了第二个参数,则会把后插入的原始值,初始化为该指定值,如果没有为 resize() 指定第二个参数,则会把新插入的元素初始化为默认的初始值。

string str = "12345";
str.resize(3);				   // 结果为 123
str.resize(str.size()+2, '+');	// 结果为 123++
3.7 reserve() 改变字符串容量大小
3.8 empty() 字符串是否为空
str.empty();
3.9 clear() 清除字符串
str.clear();
3.10 substr() 获取子串
string s = "abcdefg";
// s.substr(pos1,n) : 返回字符串位置为pos1后面的n个字符组成的串
string s2 = s.substr(1, 5);// bcdef

// s.substr(pos) : 得到一个pos到结尾的串
string s3 = s.substr(4); // efg
3.11 push_back() 末尾追加一个字符
str.push_back('c');	 // 末尾追加一个字符'c'
str += "c";			// 末尾追加一个字符串"c"
str.append("c")		// 末尾追加一个字符串"c"
3.12 pop_back() 删除末尾一个字符
str.pop_back();	

以上这两个方法在 string中不常用
因为字符串追加+= 运算符,append()insert()
字符串删除erase()substr()

3.13 append() 末尾追加 字符 或 字符串
#include <iostream>
#include <string>

int main () {
    std::string str;
    std::string str2="Writing ";
    std::string str3="print 10 and then 5 more";

    //直接追加一个str2的字符串
    str.append(str2);                       // "Writing "
    //后面追加str3第6个字符开始的3个字符串
    str.append(str3, 6, 3);                   // "10 "
    //追加字符串形参的前5个字符
    str.append("dots are cool", 5);          // "dots "
    //直接添加
    str.append("here: ");                   // "here: "
    //添加10个'.'
    str.append(10u, '.');                    // ".........."
    //添加str3迭代器范围的字符串
    str.append(str3.begin()+8, str3.end());  // " and then 5 more"
    //最后这个比较特殊,意思是添加5个'A',实际上参数里面的65对应的asc码就是65
    str.append<int>(5, 65);                // "....."
    //字符串追加也可以用重载运算符实现
    str += "lalala";
    std::cout << str << '\n';
    return 0;
}
3.14 insert() 插入
#include <iostream>
using namespace std;
int main(){
    string str="to be question";
    string str2="the ";
    string str3="or not to be";
    string::iterator it;

    //s.insert(pos,str): 在s的pos位置插入str,下标从0开始
    str.insert(6,str2);                 // to be the question

    //s.insert(pos,str,a,n): 在s的pos位置插入str中插入位置a到后面的n个字符
    str.insert(6,str3,3,4);             // to be not the question

    //s.insert(pos,cstr,n): 在pos位置插入cstr字符串从开始到后面的n个字符
    str.insert(10,"that is cool",8);    // to be not that is the question

    //s.insert(pos,cstr): 在s的pos位置插入cstr
    str.insert(10,"to be ");            // to be not to be that is the question

    //s.insert(pos,n,ch): 在s.pos位置上面插入n个ch
    str.insert(15,1,':');               // to be not to be: that is the question

    //s.insert(s.it,ch): 在s的it指向位置前面插入一个字符ch,返回新插入的位置的迭代器
    it = str.insert(str.begin()+5,','); // to be, not to be: that is the question

    //s.insert(s.it,n,ch): 在s的it所指向位置的前面插入n个ch
    str.insert(str.end(),3,'.');       // to be, not to be: that is the question...

    //s.insert(it,str.ita,str.itb): 在it所指向的位置的前面插入[ita,itb)的字符串
    str.insert (it+2,str3.begin(),str3.begin()+3); // to be, or not to be: that is the question...

    return 0;
}
3.15 replace() 替换

replace支持使用无符号整数寻找位置,也支持用迭代器寻找位置

#include <iostream>
#include <string>
using namespace std;
int main () {
    string base = "this is a test string.";
    string str2 = "n example";
    string str3 = "sample phrase";
    string str4 = "useful.";

    // replace signatures used in the same order as described above:

    // Using positions:                 0123456789*123456789*12345
    string str = base;              // "this is a test string."
    // 第9个字符以及后面的4个字符被str2代替
    str.replace(9, 5, str2);          // "this is an example string." (1)
    // 第19个字符串以及后面的5个字符用str3的第7个字符以及后面的5个字符代替
    str.replace(19, 6, str3, 7, 6);     // "this is an example phrase." (2)
    // 第8个字符以及后面的9个字符用字符串参数代替
    str.replace(8, 10, "just a");     // "this is just a phrase."     (3)
    // 第8个字符以及后面的5个字符用字符串参数的前7个字符替换
    str.replace(8, 6, "a shorty", 7);  // "this is a short phrase."    (4)
    // 第22以及后面的0个字符用3个叹号替换
    str.replace(22, 1, 3, '!');        // "this is a short phrase!!!"  (5)
    // 迭代器的原理同上
    // Using iterators:                   0123456789*123456789*
    str.replace(str.begin(),str.end()-3,str3);       // "sample phrase!!!"     (1)
    str.replace(str.begin(),str.begin()+6,"replace");// "replace phrase!!!"    (3)
    str.replace(str.begin()+8,str.begin()+14,"is coolness",7);// "replace is cool!!!"  (4)
    str.replace(str.begin()+12,str.end()-4,4,'o');   // "replace is cooool!!!"  (5)
    str.replace(str.begin()+11,str.end(),str4.begin(),str4.end());// "replace is useful."  (6)
    std::cout << str << '\n';   
    return 0;
}

以上的replace操作可以用insert和erase的操作组合替换,但是replace操作更加方便。

3.16 assign() 为字符串赋新值
#include <iostream>
#include <string>
using namespace std;
int main () {
    string str;
    string base = "The quick brown fox jumps over a lazy dog.";

    // used in the same order as described above:
    // 直接把base赋值给str
    str.assign(base);
    std::cout << str << '\n';
    // 把base第10个字符以及后面的8个字符赋给str
    str.assign(base, 10, 9);
    std::cout << str << '\n';         // "brown fox"
    // 把参数中的0到6个字符串赋给str
    str.assign("pangrams are cool", 7);
    std::cout << str << '\n';         // "pangram"
    // 直接使用参数赋值
    str.assign("c-string");
    std::cout << str << '\n';         // "c-string"
    // 给str赋值10个'*'字符
    str.assign(10, '*');
    std::cout << str << '\n';         // "**********"
    // 赋值是10个'-'
    str.assign<int>(10, 0x2D);
    std::cout << str << '\n';         // "----------"
    // 指定base迭代器范围的字符串
    str.assign(base.begin()+16, base.end()-12);
    std::cout << str << '\n';         // "fox jumps over"

    return 0;
}
3.17 erase() 删除

删除操作有三种:

  • 指定pos和len,其中pos为为起始位置,pos以及后面len-1个字符串都删除
  • 迭代器,删除迭代器指向的字符
  • 迭代器范围,删除这一范围的字符串,范围左闭右开
#include <iostream>
#include <string>

int main () {
  std::string str ("This is an example sentence.");
  std::cout << str << '\n';  // "This is an example sentence."
                             
  // 直接指定删除的字符串位置第十个后面的8个字符
  str.erase(10, 8);           
  std::cout << str << '\n';  // "This is an sentence."
                            
  // 删除迭代器指向的一个字符
  str.erase(str.begin()+9);  // "This is a sentence."
  std::cout << str << '\n';

  // 删除迭代器范围的字符
  str.erase (str.begin()+5, str.end()-9); 
  std::cout << str << '\n';  // "This sentence."            
  return 0;
}
3.18 compare() 函数

由于string重载了运算符,可以直接用>、<、>=、<=、==、!=来进行比较
或者使用 compare() 函数比较,其和strcmp函数一样,如果两个字符串相等,那么返回0,调用对象大于参数返回1,小于返回-1。 在compare当中还支持部分比较,里面有6个参数可以设置。

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    string s1="123",s2="123";
    cout<<s1.compare(s2)<<endl;//0

    s1="123",s2="1234";
    cout<<s1.compare(s2)<<endl;//-1

    s1="1234",s2="123";
    cout<<s1.compare(s2)<<endl;//1

    std::string str1 ("green apple");
    std::string str2 ("red apple");

    if (str1.compare(str2) != 0)
    std::cout << str1 << " is not " << str2 << '\n';
    //str1的第6个字符以及后面的4个字符和参数比较
    if (str1.compare(6,5,"apple") == 0)
    std::cout << "still, " << str1 << " is an apple\n";

    if (str2.compare(str2.size()-5,5,"apple") == 0)
    std::cout << "and " << str2 << " is also an apple\n";
    //str1的第6个字符以及后面的4个字符和str2的第4个字符以及后面的4个字符比较
    if (str1.compare(6,5,str2,4,5) == 0)
    std::cout << "therefore, both are apples\n";
    return 0;
}

3. string 转换为 const char* 、char * 或者 char[]

1、如果要将 string 转换为 const char* ,可以使用string提供的函数 c_str() ,或是函数 data()

  • data() 除了返回字符串内容外,不附加结束符’\0’
  • c_str() 返回一个以‘\0’结尾的字符数组

2、const char *c_str()
函数返回一个指向正规C字符串的指针,内容与本string串相同。这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数 c_str() 把string 对象转换成c中的字符串样式。注意:一定要使用 strcpy() 函数 等来操作方法 c_str() 返回的指针

比如:最好不要这样

string s = "1234";
const char* p = s.c_str(); 	// c最后指向的内容是垃圾,因为s对象被析构,其内容被处理
// 加const或者用char *p = (char*)str.c_str(); 强制转换

应该使用如下方式:

3.1 调用 string的 c_str() 函数 [返回的是const char *, 或者使用(char *) 强转成 char *]
#include <iostream>
#include <string>
#include <cstring>
int main() {
  
    char p[20];
  	string str = "hello world"; 
    // c_str()函数返回一个指向正规C字符串的指针cosnt char *, 内容与本string串相同,以'\0'结尾. 
  	strcpy(p, str.c_str()); // 使用strcpy将返回的字符串拷贝至char p[] 数组
  	cout << p << endl;
}
3.2 调用 string 的 data() 函数 [返回的是const char *, 或者使用(char *) 强转成 char *]

和上面方法一致,只是返回字符串内容,不附加结束符’\0’

3.3 调用 string 的 copy() 函数 [返回的是 char *]
string str = "hello world"; 
char p[40]; 
str.copy(p, 5, 0); // 这里5,代表复制几个字符,0代表复制的位置
*(p+5)='\0';       // 要手动加上结束符!!!
cout << p << endl;

4. char * 、char []转换为 string

4.1 char * 转 string

可以直接赋值

string s;
char *p = "hello world";
s = p;
4.2 char [] 转 string

可以直接赋值

string s;
char ch[] = "hello world";
s = ch;

5. char* 与 char[] 互转

5.1 char[] 转 char*

可以直接赋值

char ch[] = "hello world";
char *p = ch;
5.2 char * 转 char[]

不能直接赋值,可以循环char*字符串逐个字符赋值,也可以使用strcpy()strcpy_s()等函数。

char *p = "hello world";
char ch[20];
strcpy(ch, p);

总结:char[] 数组转换为其他类型,可以直接赋值。

6. 查找

6.1 find() 函数

主要是查找一个字符串是否在调用的字符串中出现过,大小写敏感。

#include <iostream>
using namespace std;
int main(){
    string str ("There are two needles in this haystack with needles.");
    string str2 ("needle");

    // different member versions of find in the same order as above:
    //在str当中查找第一个出现的needle,找到则返回出现的位置,否则返回结尾
    size_t found = str.find(str2);
    if (found!=string::npos)
    cout << "first 'needle' found at: " << found << '\n';
    //在str当中,从第found+1的位置开始查找参数字符串的前6个字符
    found=str.find("needles are small",found+1,6);
    if (found!=string::npos)
    cout << "second 'needle' found at: " << found << '\n';
    //在str当中查找参数中的字符串
    found=str.find("haystack");
    if (found!=string::npos)
    cout << "'haystack' also found at: " << found << '\n';
    //查找一个字符
    found=str.find('.');
    if (found!=string::npos)
    cout << "Period found at: " << found << '\n';
    //组合使用,把str2用参数表中的字符串代替
    // let's replace the first needle:
    str.replace(str.find(str2),str2.length(),"preposition");
    cout << str << '\n';
    return 0;
}
6.2 rfind() 函数

找最后一个出现的匹配字符串,返回的位置仍然是从前往后数的。

#include <iostream>
using namespace std;

int main() {
    string str ("The sixth sick sheik's sixth sheep's sick.");
    string key ("sixth");//                    ^
    //rfind是找最后一个出现的匹配字符串
    size_t found = str.rfind(key);
    if (found!=string::npos) {
        cout<<found<<endl;//输出23
        str.replace (found,key.length(),"seventh");//找到的sixth替换成seventh
    }

    cout << str << '\n';
    return 0;
}
6.3 find_….of函数
  • find_first_of(args) :查找args中任何一个字符第一次出现的位置
  • find_last_of(args) :最后一个出现的位置
  • find_fist_not_of(args) : 查找第一个不在args中的字符
  • find_last_not_of(args) : 查找最后一个不在args中出现的字符
#include <iostream>
using namespace std;

int main() {
    string str1 ("Please, replace the vowels in this sentence by asterisks.");
    size_t found1 = str1.find_first_of("aeiou");
    //把所有元音找出来用*代替
    while (found1!=string::npos) {
        str1[found1]='*';
        found1=str1.find_first_of("aeiou",found1+1);
    }
    cout << str1 << '\n';

    //在str2中找到第一个不是消协英文字母和空格的字符
    string str2 ("look for non-alphabetic characters...");
    size_t found2 = str2.find_first_not_of("abcdefghijklmnopqrstuvwxyz ");
    if (found2!=string::npos) {
        cout << "The first non-alphabetic character is " << str2[found2];
        cout << " at position " << found2 << '\n';
    }
    return 0;
}   

find_last_of()find_last_not_of()first基本相同,就不写例子代码了。

7. 实例

7.1 查找给定字符串并把相应子串替换为另一给定字符串

string 并没有提供这样的函数,所以我们自己来实现。由于给定字符串可能出现多次,所以需要用到 find() 成员函数的第二个参数,每次查找之后,从找到位置往后继续搜索。直接看代码(这个函数返回替换的次数,如果返回值是 0 说明没有替换):

int str_replace(string &str, const string &src, const string &dest) {
    int counter = 0;
    string::size_type pos = 0;
    while ((pos = str.find(src, pos)) != string::npos) {
        str.replace(pos, src.size(), dest);
        ++counter;
        pos += dest.size();
    }
    return counter;
}
7.2 从给定字符串中删除一给定字串

方法和上面相似,内部使用 erase() 完成。代码:

int str_erase(string &str, const string src) {
    int counter = 0;
    string::size_type pos = 0;
    while ((pos = str.find(src, pos)) != string::npos) {
        str.erase(pos, src.size());
        ++counter;
    }
    return counter;
}
7.3 给定一字符串和一字符集,从字符串剔除字符集中的任意字符
int str_wash(string &str, const string src) {
    int counter = 0;
    string::size_type pos = 0;
    while ((pos = str.find_first_of(src, pos)) != string::npos) {
        str.erase(pos, 1);
        ++counter;
    }
    return counter;
}
7.4 分割字符串(以逗号分隔符为例,分割得到相应数字)
/*
    输入一连串数字,数字之间逗号隔开,把数字存到数组或者向量里。
*/
#include <iostream>
#include <string>
#include <vector>
#include <stdio.h>
using namespace std;

int main() {
    string str_input;
    cout<<"输入一串以逗号为分隔符的数字字符串:"<<endl;
    while(cin >> str_input) {
        vector<int> nums;
        // string->char *
        char *s_input = (char *)str_input.c_str();
        const char * split = ",";
        // 以逗号为分隔符拆分字符串
        char *p = strtok(s_input, split);

        int a;
        while(p != NULL) {
            // char * -> int
            sscanf(p, "%d", &a);
            nums.push_back(a);
            p=strtok(NULL, split);
        }

        cout<<"输出得到的数字:"<<endl;
        for(a = 0; a < nums.size(); a++) {
            cout<<nums[a]<<endl;
        }
    }
    return 0;
}

8. 数值转换:

在io的部分有过数值和字符串相互转换的例子,使用的是stringstream函数,在c++11当中有定义好的现成的函数取调用,非常方便。

string和数值转换
to_string(val)把val转换成string
stoi(s,p,b)把字符串s从p开始转换成b进制的int
stol(s,p,b)long
stoul(s,p,b)unsigned long
stoll(s,p,b)long long
stoull(s,p,b)unsigned long long
stof(s,p)float
stod(s,p)double
stold(s,p)long double

//注意,下段代码在MinGw中会报错!即使使用c++11编译也一样,无法识别to_string!

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    string s1;
    s1=to_string(100);
    cout<<s1<<endl;
    int a=stoi(s1,0,10)+1;
    cout<<a<<endl;
    return 0;
}

9. Reference

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值