当前位置:   article > 正文

从C到C++___标准string类_csdn shawn summer

csdn shawn summer

标准string类

我们一直都在使用string类,C++string类是C风格字符串的替代品。这篇文章主要是看看string类的构造函数和一些接口,重点在于如何使用string类。
在研究string类之前,我先表明,这篇文章主要是忽略了两个事实:string类实际上是模板具体化basic_string<char>的一个typedef,而且我们不在意string类的内存管理。

1. 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;

}
  • 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
Lottery Winner!
$$$$$$$$$$$$$$$$$$$$
Lottery Winner!
Lottery Winner! Oops!
Sorry! That was Pottery Winner!
All's well that ends!
well, well...
That was Pottery in motion!
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

string类重载了+=符号,=符号,+符号,<<符号,[]符号。
而且这里的+==+符号能适配,C风格字符串,string对象,单个字符。
例如:

one+='!';
two="adsasd";
three+=two;
  • 1
  • 2
  • 3
  • C++11 新增的构造函数

string(string && str)类似于复制构造函数,导致新创建的stringstr的副本,但是修改新的对象不会改变str。但与复制构造函数不同的使,它不保证将str视为const。这种构造函数被称为移动构造函数

string(initializer_list<char> il)让我们可以将列表初始化语法用于string类。即

string piano_man={'L','i','s','z','t'};
string piano_lang{'L','i','s','p'};
  • 1
  • 2

2.string类的输入

首先看一下,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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
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.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

对于C风格字符串,输入有4种方式

  • cin>>info;//read a word,leave \n in queue
  • cin.getline(info,100);//read a line,discard \n
  • cin.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;
    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
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.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

对于string对象,输入有3种方式:

  • cin>>stuff;//read a word,leave \n in queue
  • getline(cin,stuff);//read a line,discard \n
  • getline(cin,staff,'#');//read until '#',discard '#'

关于C风格字符串和string对象的输入区别:
实际上,它们两几乎毫无关系,C风格字符串使用的cinistream类的方法,而string对象的cingetlinestring类的友元函数。
而且在功能上来说,我们输入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();
    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

注意,我们将':'作为分界字符后,换行符就会被读取,所以第9个getline(),唯一得到的字符就是换行符。

3.使用string

可以比较字符串string对象重载了全部6个关系运算符,包括<>==>=<=!=。而且这些重载运算符都可以与C风格字符串进行比较。和<cstring>中的std::strcmp()差不多。

可以确定字符串的长度(不包括空字符)size()length()成员函数都可以返回字符串中的非空字符数:

if(snake1.length()==snake2.size())
    cout<<"match\n";
  • 1
  • 2

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";
    }
    
}
  • 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
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
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!
  • 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

4.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;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
Size:
empty: 0
small: 3
larger: 35
capacities: 
empty: 15
small: 15
Larger: 35
Capacity after empty.reserve(50):
50
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • string::capacity()

由于string类给每个对象都动态分配了内存,这个函数的返回值就是分配的内存大小。

  • string::reserve(int n=0);

这个函数相当于是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;
  • 1
  • 2
  • 3
  • 4

上面这些都是不同的string类


  1. NBTS指C风格字符串。 ↩︎

  2. size_type是一个依赖于实现的整型,是在头文件string中定义的。 ↩︎

  3. string::npos为字符串的最大长度,通常为65535 ↩︎

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/236723?site
推荐阅读
相关标签
  

闽ICP备14008679号