C++:string的使用
1.auto关键字
2.范围for
3.迭代器
4.string的相关函数的使用
1.auto关键字
- C++11中,auto作为一个新的类型指示符 来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
- 用auto声明指针类型 时,用auto和auto*没有任何区别,但用auto声明引用类型 时则必须加 & 。
- 在同一行声明多个变量 时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
- auto不能作为函数的参数,可以做返回值,但是慎用。
- auto不能直接用来声明数组 。
cpp
#include<iostream>
using namespace std;
int main()
{
int a=10;
auto b=a;
auto c='a';
cout<<typeid(b).name()<<endl;//typeid(变量).name()可得变量的类型
cout<<typeid(c).name()<<endl;
return 0;
}

cpp
#include<iostream>
using namespace std;
int main()
{
auto d;//编译报错
return 0;
}

2.范围for
- 对于一个有范围的集合 ,for循环后的括号由冒号 : 分为两部分,第一部分是范围内用于迭代的变量 ,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
- 范围for可以作用到数组 和容器对象 上进行遍历 。
- 范围for的底层很简单,容器遍历实际就是替换为迭代器。
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
for(auto ch:s)
{
cout<<ch;
}
return 0;
}

cpp
#include<iostream>
using namespace std;
int main()
{
int arr[]={1,2,3,4,5};
for(auto n:arr)//不改变arr的内容
{
n*=2;
cout<<n<<" ";
}
cout<<endl;
for(auto& n:arr)//改变arr的内容
{
n*=2;
cout<<n<<" ";
}
return 0;
}




3.迭代器
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
string::iterator it=s.begin();//也可写成 auto it=s.begin();
while(it!=s.end())
{
cout<<*it;
it++;
}
return 0;
}

由上述代码可以看到,iterator是类似指针的东西,但不是指针,所有容器都可以用这种类似的方式访问。

cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
string::iterator it = s.begin();
cout << typeid(string::iterator).name() << endl;
cout << typeid(it).name() << endl;
cout << typeid(s.begin()).name() << endl;
return 0;
}

从类型上也可以看到,iterator的确不是指针。
反向迭代器
可以反向遍历字符串。
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
string::reverse_iterator rit=s.rbegin();
while(rit!=s.rend())
{
cout<<*rit;
rit++;
}
return 0;
}

const迭代器与反向迭代器
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
const string s("hello world");
string::const_iterator cit=s.begin();
while(cit!=s.end())
{
cout<<*cit;
cit++;
}
return 0;
}

cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
string::const_reverse_iterator rcit=s.rbegin();
while(rcit!=s.rend())
{
cout<<*rcit;
rcit++;
}
return 0;
}

综上,迭代器有4种:iterator、reverse_iterator、const_iterator、const_reverse_iterator 。
4.string的相关函数的使用
下面介绍string相关函数的常见使用,具体使用可在 https://legacy.cplusplus.com/ 查询。

reserve与push_back
reserve可以提前开好所需空间,避免扩容,提高效率。
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1;
s1.reserve(100);
string s2("abcde");
s2.reserve(10);
string s3("abcde");
s3.reserve(3);//空间开少了是不会缩容的
return 0;
}
push_back可以在字符串末尾尾插字符。
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
cout<<s<<endl;
s.push_back('#');
cout<<s<<endl;
return 0;
}

求字符串的长度
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
cout<<s.size()<<endl;
return 0;
}

在字符串后追加一个字符串
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1("hello world");
s1.append("%%%");
cout<<s1<<endl;
string s2("hello world");
s2+="$$$"; //更常用
cout<<s2<<endl;
return 0;
}

指定位置插入字符或字符串
插入字符串:
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1("hello world");
s1.insert(0,"p");
cout<<s1<<endl;
string s2("hello world");
s2.insert(10,"zzz");
cout<<s2<<endl;
return 0;
}

插入字符:
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
char ch='@';
string s1("hello world");
s1.insert(0,1,ch);//从下标为0的位置插入1个字符ch
cout<<s1<<endl;
string s2("hello world");
s2.insert(s2.begin(),ch);
cout<<s2<<endl;
return 0;
}

在指定位置删除字符
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
s.erase(5,2); //从下标5开始删2个字符
cout<<s<<endl;
return 0;
}

cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1("hello world");
s1.erase(0,1); //头删
cout<<s1<<endl;
string s2("hello world");
s2.erase(s2.begin()); //头删
cout<<s2<<endl;
return 0;
}

cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1("hello world");
s1.erase(--s1.end()); //尾删
cout<<s1<<endl;
string s2("hello world");
s2.erase(s2.size()-1,1); //尾删
cout<<s2<<endl;
return 0;
}

cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
s.erase(6); //删除从下标6开始的所有字符
cout<<s<<endl;
return 0;
}

find
在字符串中从头开始找指定字符,返回该字符第一次出现的位置,未找到则返回npos。
例如:把字符串中的空格替换为"%%"。
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
size_t pos=s.find(' ');//找到s中第一个空格的位置
while(pos!=string::npos)//只要找得到循环就继续
{
s.replace(pos,1,"%%");//把从下标pos开始的1个字符替换为"%%"
cout<<s<<endl;
pos=s.find(' ',pos+2);//把空格改为"%%"后修正pos,使find不必从头开始找空格
}
return 0;
}

也可以使用另一种写法,效果相同。
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
string t;
t.reserve(s.size());//提前开好空间,此时t为空字符串
for(auto ch:s)//遍历字符串s
{
if(ch==' ')//遇到空格则追加"%%"
t+="%%";
else
t+=ch;
}
s.swap(t);//交换s与t的内容
cout<<s<<endl;
return 0;
}



类似的还有rfind,与find不同的是rfind从后往前找。
substr
从下标pos开始,截取n个字符并将其返回。
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello world");
cout<<s.substr(4,3)<<endl;
return 0;
}

c_str
C++的字符串的类型是string,是一个类类型,而C语言的字符串是char*类型。
可以用c_str把C++的字符串转成C格式的字符串,从而适配C 。
c_str()的返回类型是const char*
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("This is CPP.");
const char* p=s.c_str();
return 0;
}

+和=
cpp
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1("hello");
string s2=s1+"world";
cout<<s2<<endl;
string s3="world"+s1;
cout<<s3<<endl;
return 0;
}

拙作一篇,望诸位同道不吝斧正。