赞
踩
我们一直都在使用string
类,C++string
类是C风格字符串的替代品。这篇文章主要是看看string
类的构造函数和一些接口,重点在于如何使用string
类。
在研究string
类之前,我先表明,这篇文章主要是忽略了两个事实:string
类实际上是模板具体化basic_string<char>
的一个typedef
,而且我们不在意string
类的内存管理。
string
类的 构造函数构造函数 | 描述 |
---|---|
string(const char *s) | 将string 对象初始化为s指向的NBTS 1 |
string(size_type2 n,char c) | 创建一个包含n个元素的string对象,其中每个元素都初始化为字符c |
string(const string & str) | 复制构造函数 |
string() | 默认构造函数,长度为0的对象 |
string(const char* s,size_type n) | 将string对象初始化为s指向的NBTS的前n个字符,即使超过了NBTS结尾 |
template<class Iter> string(Iter begin,Iter end) | 将string对象初始化为区间[begin,end)内的字符,其中begin和end行为就像指针,用于指定位置。 |
string(const string &str,size_type pos,size_type n=npos3) | 将一个string对象初始化为对象str从位置pos开始到结尾的字符,或者从位置pos开始的n个字符 |
string(string && str)noexcept | 移动构造函数,它将一个string对象初始化为对象str,并可能修改str |
string(initializer_list<char> il) | 将一个string对象初始化为初始化列表il中的字符。 |
一个例子:
//标准string1.cpp #include<iostream> #include<string> int main() { using namespace std; string one("Lottery Winner!");//ctor#1 cout<<one<<endl; string two(20,'$');//ctor#2 cout<<two<<endl; string three(one);//ctor#3 cout<<three<<endl; one+=" Oops!";//overload += cout<<one<<endl; two="Sorry! That was ";//overload = three[0]='P';//overload [] string four;//ctor#4 four=two+three;//overload + cout<<four<<endl; char alls[]="All's well that ends well"; string five(alls,20);//ctor#5 cout<<five<<"!\n"; string six(alls+6,alls+10);//ctor#6 cout<<six<<", "; string seven(&five[6],&five[10]);//ctor#6 agian cout<<seven<<"...\n"; string eight(four,7,16);//ctor#7 cout<<eight<<" in motion!"<<endl; }
Lottery Winner!
$$$$$$$$$$$$$$$$$$$$
Lottery Winner!
Lottery Winner! Oops!
Sorry! That was Pottery Winner!
All's well that ends!
well, well...
That was Pottery in motion!
string
类重载了+=
符号,=
符号,+
符号,<<
符号,[]
符号。
而且这里的+=
、=
、+
符号能适配,C风格字符串,string对象,单个字符。
例如:
one+='!';
two="adsasd";
three+=two;
string(string && str)
类似于复制构造函数,导致新创建的string
为str
的副本,但是修改新的对象不会改变str
。但与复制构造函数不同的使,它不保证将str
视为const
。这种构造函数被称为移动构造函数。
string(initializer_list<char> il)
让我们可以将列表初始化语法用于string
类。即
string piano_man={'L','i','s','z','t'};
string piano_lang{'L','i','s','p'};
首先看一下,C风格字符串的输入:
#include<iostream> int main() { using namespace std; char info[100]; cout<<"Enter the string: "; cin>>info; cout<<"The string :"<<info<<endl; cin.get();//吸收换行符 cout<<"Enter the string: "; cin.getline(info,100);//read a line,discard \n cout<<"The string :"<<info<<endl; cout<<"Enter the string: "; cin.get(info,100);//read a line ,leave \n in queue cout<<"The string :"<<info<<endl; cin.get();//吸收换行符 cout<<"Enter the string: "; cin.getline(info,100,':'); cout<<"The string :"<<info<<endl; }
Enter the string: apple
The string :apple
Enter the string: cat dog animals
The string :cat dog animals
Enter the string: cat dog animals
The string :cat dog animals
Enter the string: i am a boy,
and i love turtles.:
The string :i am a boy,
and i love turtles.
对于C风格字符串,输入有4种方式
cin>>info;
//read a word,leave \n in queuecin.getline(info,100);
//read a line,discard \ncin.getline(info,100,'$');
//read until '$'
,discard '$'
cin.get(info,100);
//read a line,leave \n in queue下面是,string
对象的输入方式:
#include<iostream> #include<string> int main() { using namespace std; string stuff; cout<<"Enter the string: "; cin>>stuff; cout<<"the string: "<<stuff<<endl; cin.get();//吸收换行符 cout<<"Enter the string: "; getline(cin,stuff); cout<<"the string: "<<stuff<<endl; cout<<"Enter the string: "; getline(cin,stuff,'#'); cout<<"the string: "<<stuff<<endl; }
Enter the string: apple
the string: apple
Enter the string: cat dog animals
the string: cat dog animals
Enter the string: i am a boy,
and i love turtles.#
the string: i am a boy,
and i love turtles.
对于string
对象,输入有3种方式:
cin>>stuff;
//read a word,leave \n in queuegetline(cin,stuff);
//read a line,discard \ngetline(cin,staff,'#');
//read until '#'
,discard '#'
关于C风格字符串和string
对象的输入区别:
实际上,它们两几乎毫无关系,C风格字符串使用的cin
是istream
类的方法,而string
对象的cin
和getline
是string
类的友元函数。
而且在功能上来说,我们输入string
对象时,不需要提供目标对象的大小。
string
对象的输入异常问题:
string
版本的getline()
函数会从输入种读取字符,并将其存到目标对象种,直到发生如下情况
eofbit
被设置,fail()
和eof()
都将返回true
;\n
),这种情况下将分界字符从输入流中删除,但是不存储它;failbit
被设置,fail()
会返回true
;string
版本的operator>>()
函数行为与上面类似,只是他会跳过空白字符(空格,换行符,制表符),把空白字符留在输入队列中,然后开始读取直到遇到分界字符,把它留在输入流中。
总之,以上的知识,都会在使用cin
中详细解释。
一个例子:
//标准string4.cpp #include<iostream> #include<fstream> #include<string> int main() { using namespace std; ifstream fin; fin.open("tobuy.txt"); string item; int count=0; getline(fin,item,':'); while (fin) { ++count; cout<<count<<": "<<item<<endl; getline(fin,item,':'); } cout<<"Done\n"; fin.close(); }
tobuy.txt
文件中内容为:
sardines:chocolate ice cream:pop corn:leeks:
cottage cheese:olive oil:butter:tofu:
1: sardines
2: chocolate ice cream
3: pop corn
4: leeks
5:
cottage cheese
6: olive oil
7: butter
8: tofu
9:
Done
注意,我们将':'
作为分界字符后,换行符就会被读取,所以第9个getline()
,唯一得到的字符就是换行符。
string
可以比较字符串。string
对象重载了全部6个关系运算符,包括<
、>
、==
、>=
、<=
、!=
。而且这些重载运算符都可以与C风格字符串进行比较。和<cstring>
中的std::strcmp()
差不多。
可以确定字符串的长度(不包括空字符)。size()
和length()
成员函数都可以返回字符串中的非空字符数:
if(snake1.length()==snake2.size())
cout<<"match\n";
length()
成员来自早期string
类,而size()
则是为STL兼容性而添加的。
可以以多种不同的方式在字符串中搜索给定的子字符串或字符。
方法原型 | 描述 |
---|---|
size_type find(const string & str,size_type pos=0) const | 从pos位置开始,查找字符串str。如果找到,返回该字符串首次出现时其首字符的索引;否则,返回string::npos |
size_type find(const char *s,size_type pos=0) const | 从pos位置开始,查找字符串s。如果找到,返回该字符串首次出现时其首字符的索引;否则,返回string::npos |
size_type find(const char*s,size_type pos,size_type n) const | 从pos位置开始,查找s的前n个字符组成的子字符串。如果找到,返回该字符串首次出现时其首字符的索引;否则,返回string::npos |
size_type find(char ch,size_type pos=0) const | 从字符串的pos位置开始,查找字符ch。如果找到,则返回该字符首次出现的索引;否则,返回string::npos; |
string库还提供了相关的方法:
rfind()
、find_first_of()
、find_last_of()
、find_first_not_of()
、find_last_not_of()
,它们的重载函数特征标都与find()
方法相同。rfind()
方法查找子字符串或字符最后一次出现的索引;find_first_of()
方法在字符串中查找参数中,任何一个字符首次出现的位置。例如,下面的语句返回r
在"cobra"
中的位置,因为"hark"
中各个字母在"cobra"
首次出现的位置:
int where = snake1.find_first_of("hark");
find_last_of()
方法的功能与此相同,只是它查找的是最后一次出现的位置。因此,下面的语句返回a
在"cobra"
中的位置:
int where = snake1.find_last_of("hark");
find_first_not_of()
方法在字符串中查找第一个不包含在参数中的字符,因此下面的语句返回c
在"cobra"
中的位置:
int where = snake1.find_first_not_of("hark");
find_last_not_of()
方法功能与此相同,只是它查找的是最后一次出现的位置。
我们使用之前学过的知识,可以设计一个猜词游戏:
//标准string5.cpp #include<iostream> #include<string> int main() { using namespace std; string target; int guesses=10; cout<<"Enter the target word: "; cin>>target; int length=target.length(); string attempt(length,'-'); string Badchoice; while (guesses!=0 && attempt!=target) { char a; cout<<"your word: "<<attempt<<endl; cout<<"guess a letter: "; cin>>a; if(Badchoice.find(a)!=string::npos || attempt.find(a)!=string::npos) { cout<<"You already guessed that.\n"; continue; } int index=target.find(a); if(index!=string::npos) { cout<<"good guess\n"; attempt[index]=a; index=target.find(a,index+1); while (index!=string::npos) { attempt[index]=a; index=target.find(a,index+1); } } else { cout<<"Bad guesses!\n"; guesses--; cout<<"you have "<<guesses<<" badguesses left\n"; Badchoice+=a; } if(Badchoice.length()) cout<<"Bad choice: "<<Badchoice<<endl; } if(guesses==0) { cout<<"what a pity\n"; } else { cout<<"conguatulations!\n"; } }
Enter the target word: batman your word: ------ guess a letter: a good guess your word: -a--a- guess a letter: b good guess your word: ba--a- guess a letter: o Bad guesses! you have 9 badguesses left Bad choice: o your word: ba--a- guess a letter: e Bad guesses! you have 8 badguesses left Bad choice: oe your word: ba--a- guess a letter: n good guess Bad choice: oe your word: ba--an guess a letter: f Bad guesses! you have 7 badguesses left Bad choice: oef your word: ba--an guess a letter: g Bad guesses! you have 6 badguesses left Bad choice: oefg your word: ba--an guess a letter: i Bad guesses! you have 5 badguesses left Bad choice: oefgi your word: ba--an guess a letter: m good guess Bad choice: oefgi your word: ba-man guess a letter: t good guess Bad choice: oefgi conguatulations!
string
的其它实用接口string
库还提供了很多工具,包括:删除字符串的部分或全部内容、插入字符串、删除字符、提取、交换等等众多功能。具体细节请参照cplusplus,这个网址s是最好的C++语法教材。
#include<iostream> #include<string> int main() { using namespace std; string empty; string small="bit"; string larger="Elephants are a girl's best friends"; cout<<"Size:\n"; cout<<"empty: "<<empty.size()<<endl; cout<<"small: "<<small.size()<<endl; cout<<"larger: "<<larger.size()<<endl; cout<<"capacities: \n"; cout<<"empty: "<<empty.capacity()<<endl; cout<<"small: "<<small.capacity()<<endl; cout<<"Larger: "<<larger.capacity()<<endl; empty.reserve(50); cout<<"Capacity after empty.reserve(50):\n"; cout<<empty.capacity()<<endl; }
Size:
empty: 0
small: 3
larger: 35
capacities:
empty: 15
small: 15
Larger: 35
Capacity after empty.reserve(50):
50
由于string
类给每个对象都动态分配了内存,这个函数的返回值就是分配的内存大小。
这个函数相当于是malloc,如果n比当前已分配内存大,那么就会给这个对象分配n个字节的内存,或者更大。
还有一个很重要的接口:string::c_str();
这个接口返回一个C风格的字符串。
typedef basic_string<char> string;
typedef basic_string<wchar_t>wstring;
typedef basic_string<char16_t>u16string;
typedef basic_string<char32_t>u32string;
上面这些都是不同的string类
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。