C++字符串详解

参考:书本《C++ Primer Plus》


c++中的字符串有两种:c-风格字符串和基于string类库的方法
c-风格字符串以空字符结尾(’\0’)
使用引号括起的字符串隐式地包括结尾的空字符
string转为c-风格字符串:c_str()方法(str.c_str()


字符串

  • 字符串常量与字符常量

    使用双引号的为字符串常量,使用单引号的是字符常量两者不能互换
    字符串常量是字符编码的简写表示。在ASCII系统上,'S’只是83的另一种写法。
    char string_size = 'S'; //allowed
    但"S"不是字符串常量,它表示的是两个字符(字符S和\0)组成的字符串,"S"实际上表示的是字符串所在的内存地址。
    char string_size = "S"; //not allowed

  • 拼接字符串常量

    任何两个由空白(空格、制表符、换行符)分隔的字符串常量都将自动拼接成一个。

    cout << "abcd""efg" << endl;//输出:abcdefg
    cout << "abcd" "efg" << endl;//输出:abcdefg
    cout << "abcd" 
    	"efg" << endl;//输出:abcdefg
    

    拼接时不会在被连接的字符串之间添加空格,第二个字符串的第一个字符紧跟在第一个字符串的最后一个字符(不考虑\0)后面,第二个字符串的第一个字符取代第一个字符串的\0字符。

  • 在数组中使用字符串

    const int Size = 15;
    char arr[Size] = "C++boy"; //初始化数组
    cout << sizeof(arr) << endl; //输出:15
    cout << strlen(arr) << endl; //输出:6
    arr[3] = '\0';
    cout << arr << endl; //输出:C++
    

    sizeof()计算数组的长度,strlen()返回存储在数组中的字符串的长度,且只计算可见字符,空字符不算在内。空字符后面的字符均被忽略。

  • 字符串输入

    cin使用空白来确定字符串的结束位置,也就是说获取输入时只读取一个单词。读取单词后,cin将该字符串放到数组中,并自动在结尾添加空字符。

    • 每次读取一行字符串输入

      读取行输入函数:getline()get(),读取一行输入直到到达换行符。随后,getline()丢弃换行符,而get()将换行符保留在输入队列中。

    1. 方法一调用:cin.getline(name,20),最多读取19个字符存入name中,剩下一个字符空间存储末尾自动添加的空字符。当读取指定数目的字符或遇到换行符时停止读取。
    2. 方法二调用:cin.get(name,20)不丢弃换行符,保留在输入队列中,所以连续两次调用时第二次调用读取的第一个字符是上一次输入最后遗留下来的换行符,解决这一问题是在第一次调用后调用cin.get(),吸收换行符,接下来再进行第二次调用即可。
      或合并两次调用:cin.get(name,20).get(),同样getline()方法也可以合并两次调用:cin.getline(name,20).getline(age,8),将输入中连续的两行分别读入到数组nameage中。
    • 混合输入数字与字符串:

      const int Size = 15;
      char arr[Size] ; //初始化数组
      int a;
      cin >> a;
      cin.get(arr, 20);
      

      数组arr中是一个换行符。是输入a后遗留在输入队列中的字符。如要正常接受字符串输入,需要在cin >> a后加上cin.get()吸收掉末尾的换行符。如下,则能达成输入目的。

      const int Size = 15;
      char arr[Size] ; //初始化数组
      int a;
      cin >> a;
      cin.get();//吸收输入a后的换行符
      cin.get(arr, 20);
      

    tips:cincin.get(),前者自动跳过空白字符,后者可接受空白读取。若用cin读取字符,输入abc de f g,输出显示为abcdefg(不显示空格),cin.get()则会保留空格输出。


String类

要使用string类,必须在头文件中包含头文件string#include <string>(新版本不包含也可使用)。string类具有自动调整string大小的功能。
string对象和字符数组相同点在于,可以使用cin接受输入,cout显示输出,可以使用数组表示法访问存储在string对象中的字符(如:str[2],字符串第三个字符)。string对象和字符数组主要区别在于,可以将string对象声明为简单变量,而不是数组:

string str1;//创建一个空的string对象
string str2 = "lyh";//创建一个初始化的string对象
  • 赋值、拼接、长度

  1. 赋值
    赋值时不可以将一个数组赋给另一个数组,但是可以将一个string对象赋给另一个string对象:

    string str1;
    string str2 = "lyh";
    str1 = str2;//valid
    
  2. 拼接
    可以使用运算符++=

    string str3;
    str3 = str1 + str2;//str1和str2拼接后赋值给str3
    str1 += str2;//将字符串str2加到str1末尾
    
  3. 字符串长度

    int len1 = str1.size();//计算string类字符串长度,亦可调用length():int len1 = str1.length()
    int len2 = strlen(charr1);//计算字符串数组长度
    
  • string类I/O

    cincout句法和C-风格字符串用法相同,但读取一行而不是一个单词时,用法不同。

    cin.getline(charr,20);//读取一行到数组
    getline(cin,str);//读取一行到string对象
    

    上面两个版本的getline都有一个可选参数,用于指定使用哪个字符来确定输入的边界。

    cin.getline(charr,20,':');//读取输入直到':'字符,不包含':'字符
    getline(cin,str,':');//读取输入直到':'字符,不包含':'字符
    

    注意:将':'指定为分界字符后,换行符将被视为常规字符

    string s;
    getline(cin,s, ':');
    int count = 0;
    while (cin.fail() == false) //命令行窗口用<CTRL>+<Z><ENTER>退出,cin.fail()==true
    {
    	++count;
    	cout << count << ": " << s << endl;
    	getline(cin, s, ':');
    }
    /*Result:
    输入:
    ab: c:d:
    输出:
    1:ab
    2:  c
    3: d
    继续输入:
    e:
    输出:
    4:       //这边多出一个空行,是因为上次输入队列末尾遗留的换行符,分界字符换为':'后,换行符变成普通字符。
    e
    */
    
  • 数据方法

    方法返回值
    begin()指向字符串第一个字符的迭代器
    cbegin()一个const_iterator,指向字符串中第一个字符(C++11)
    end()超尾值的迭代器(超尾值:末尾值的下一个)
    cend()超尾值的const_iteration(C++11)
    rbegin()为超尾值的反转迭代器
    crbegin()为超尾值的反转const_iteration(C++11)
    rend()指向第一个字符的反转迭代器
    crend()指向第一个字符的反转const_iteration(C++11)
    size()字符串中的元素数 ,等于begin()到end()之间的距离
    length()与size()相同
    capacity()给字符串分配的内存块大小。可能大于实际的字符数。
    max_size()字符串的最大长度

    capacity()方法说明:因为string自动调整字符串大小,,若增加字符串长度,需要扩大内存(连续的),原来占据扩充内存的区域需要重新分配。为了避免频繁进行这种操作,降低效率,实际给string划分一块比字符串大的内存块,为字符串提供了增大空间。如果字符串不断增大,超过了内存块的大小,程序将分配一个大小为原来两倍的新内存块,以提供足够的增大空间,避免不断分配新的内存块。

    字符串存取:operator方法(str[2])和at()方法(str.at(2)),主要差别在于at()方法执行边界检查。如果pos>=size(),将引发out of range异常。而operator方法不进行边界检查,但是执行速度快,如果pos>=size(),其行为将是不确定的。
    返回字符串的子字符串str.substr(pos,n),返回一个从字符串str的pos位置开始复制n个字符的子字符串。

  • 字符串搜索

    1.find()

    函数原型
    string (1) : size_t find (const string& str, size_t pos = 0) const noexcept;
    c-string (2) :size_t find (const char* s, size_t pos = 0) const;
    buffer (3) :size_t find (const char* s, size_t pos, size_type n) const;
    character (4) :size_t find (char c, size_t pos = 0) const noexcept;

    第一个返回str在调用对象中第一次出现时的起始位置,搜索从pos开始,如果没有找到子字符串,将返回npos。
    第三个方法完成相同的工作,但是只查找待查找字符数组的前n个字符

    // string::find
    #include <iostream>       // std::cout
    #include <string>         // std::string
    
    int main ()
    {
      std::string str ("There are two needles in this haystack with needles.");
      std::string str2 ("needle");
    
      // different member versions of find in the same order as above:
      std::size_t found = str.find(str2);
      if (found!=std::string::npos)
        std::cout << "first 'needle' found at: " << found << '\n';
    
      found=str.find("needles are small",found+1,6);
      if (found!=std::string::npos)
        std::cout << "second 'needle' found at: " << found << '\n';
    
      found=str.find("haystack");
      if (found!=std::string::npos)
        std::cout << "'haystack' also found at: " << found << '\n';
    
      found=str.find('.');
      if (found!=std::string::npos)
        std::cout << "Period found at: " << found << '\n';
    
      // let's replace the first needle:
      str.replace(str.find(str2),str2.length(),"preposition");//str.replace(pos,length,string)
      std::cout << str << '\n';
    
      return 0;
    }
    /*Output:
    first 'needle' found at: 14
    second 'needle' found at: 44
    'haystack' also found at: 30
    Period found at: 51
    There are two prepositions in this haystack with needles.
    */	
    

    2.rfind()

    find()方法相似,但是此方法搜索的是字符串最后一次出现的位置,该位置位于pos之前(包括pos)。

    3.find_first_of()

    find()方法相似,但是此方法搜索的不是整个子字符串,而是搜索子字符串中的字符首次出现的位置。

    // string::find_first_of
    #include <iostream>       // std::cout
    #include <string>         // std::string
    #include <cstddef>        // std::size_t
    
    int main ()
    {
      std::string str ("Please, replace the vowels in this sentence by asterisks.");
      std::size_t found = str.find_first_of("aeiou");
      while (found!=std::string::npos)
      {
        str[found]='*';
        found=str.find_first_of("aeiou",found+1);
      }
    
      std::cout << str << '\n';
    
      return 0;
    }
    /*Output:
    Pl**s*, r*pl*c* th* v*w*ls *n th*s s*nt*nc* by *st*r*sks.
    */	
    
    

    4.find_last_of()

    rfind()方法相似,但是此方法搜索的不是整个子字符串,而是搜索子字符串中的字符出现的最后位置。

    // string::find_last_of
    #include <iostream>       // std::cout
    #include <string>         // std::string
    #include <cstddef>         // std::size_t
    
    void SplitFilename (const std::string& str)
    {
      std::cout << "Splitting: " << str << '\n';
      std::size_t found = str.find_last_of("/\\");
      std::cout << " path: " << str.substr(0,found) << '\n';
      std::cout << " file: " << str.substr(found+1) << '\n';
    }
    
    int main ()
    {
      std::string str1 ("/usr/bin/man");
      std::string str2 ("c:\\windows\\winhelp.exe");
    
      SplitFilename (str1);
      SplitFilename (str2);
    
      return 0;
    }
    /*Output:
    Splitting: /usr/bin/man
     path: /usr/bin
     file: man
    Splitting: c:\windows\winhelp.exe
     path: c:\windows
     file: winhelp.exe
    */	
    

    5.find_first_not_of()

    find_first_of()方法相似,但是此方法搜索第一个位于子字符串中的字符。

    6.find_last_not_of()

    find_last_of()方法相似,但是此方法搜索最后一个位于子字符串中的字符。

  • 字符串修改

    下述方法会改变字符串原来的值。

    1.append()

    函数声明功能
    string (1):string& append (const string& str);添加字符串str
    substring (2): string& append (const string& str, size_t subpos, size_t sublen);添加字符串str从subpos位置开始的sublen个字符
    c-string (3): string& append (const char* s);添加字符数组
    buffer (4): string& append (const char* s, size_t n);添加字符数组的前n个字符
    fill (5): string& append (size_t n, char c);添加n个重复字符c
    range (6): template string& append (InputIterator first, InputIterator last);添加范围[first,last)内的字符
    // appending to string
    #include <iostream>
    #include <string>
    
    int main ()
    {
      std::string str;
      std::string str2="Writing ";
      std::string str3="print 10 and then 5 more";
    
      // used in the same order as described above:
      str.append(str2);                       // "Writing "
      str.append(str3,6,3);                   // "10 "
      str.append("dots are cool",5);          // "dots "
      str.append("here: ");                   // "here: "
      str.append(10u,'.');                    // ".........."
      str.append(str3.begin()+8,str3.end());  // " and then 5 more"
      str.append<int>(5,0x2E);                // "....."  //0x2E = '.'
    
      std::cout << str << '\n';
      return 0;
    }
    /*Output:
    Writing 10 dots here: .......... and then 5 more.....
    */
    

    2.assign()

    函数声明与append()函数声明类似。与append()不同的是,assign()给字符串赋一个新值,代替现有的内容

    // string::assign
    #include <iostream>
    #include <string>
    
    int main ()
    {
      std::string str;
      std::string base="The quick brown fox jumps over a lazy dog.";
    
      // used in the same order as described above:
    
      str.assign(base);
      std::cout << str << '\n';
    
      str.assign(base,10,9);
      std::cout << str << '\n';         // "brown fox"
    
      str.assign("pangrams are cool",7);
      std::cout << str << '\n';         // "pangram"
    
      str.assign("c-string");
      std::cout << str << '\n';         // "c-string"
    
      str.assign(10,'*');
      std::cout << str << '\n';         // "**********"
    
      str.assign<int>(10,0x2D);
      std::cout << str << '\n';         // "----------"
    
      str.assign(base.begin()+16,base.end()-12);
      std::cout << str << '\n';         // "fox jumps over"
    
      return 0;
    }
    
    /* Output:
    The quick brown fox jumps over a lazy dog.
    brown fox
    pangram
    c-string
    **********
    ----------
    fox jumps over
    */
    

    3.insert()

    函数声明与上面两个大致相同,只是多了第一个参数pos:指明插入的位置。
    若返回迭代器,则迭代器指向插入的第一个字符

    // inserting into a string
    #include <iostream>
    #include <string>
    
    int main ()
    {
      std::string str="to be question";
      std::string str2="the ";
      std::string str3="or not to be";
      std::string::iterator it;
    
      // used in the same order as described above:
      str.insert(6,str2);                 // to be (the )question
      str.insert(6,str3,3,4);             // to be (not )the question
      str.insert(10,"that is cool",8);    // to be not (that is )the question
      str.insert(10,"to be ");            // to be not (to be )that is the question
      str.insert(15,1,':');               // to be not to be(:) that is the question
      it = str.insert(str.begin()+5,','); // to be(,) not to be: that is the question
      str.insert (str.end(),3,'.');       // to be, not to be: that is the question(...)
      str.insert (it+2,str3.begin(),str3.begin()+3); // (or )   //it -> str.begin()+5
    
      std::cout << str << '\n';
      return 0;
    }
    
    /* Output:
    to be, or not to be: that is the question...
    */
    

    4.replace()

    replace()与上述方法1、2函数参数多了两个:第一个pos:指明替换的位置,第二个len:指明被替换字符数。若是迭代器形式,则第一第二个参数变为迭代器起始末尾的位置(范围:[ , ))

    // replacing in a string
    #include <iostream>
    #include <string>
    
    int main ()
    {
      std::string base="this is a test string.";
      std::string str2="n example";
      std::string str3="sample phrase";
      std::string str4="useful.";
    
      // replace signatures used in the same order as described above:
    
      // Using positions:                 0123456789*123456789*12345
      std::string str=base;           // "this is a test string."
      str.replace(9,5,str2);          // "this is an example string." (1)
      str.replace(19,6,str3,7,6);     // "this is an example phrase." (2)
      str.replace(8,10,"just a");     // "this is just a phrase."     (3)
      str.replace(8,6,"a shorty",7);  // "this is a short phrase."    (4)
      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;
    }
    
    /* Output:
    replace is useful.
    */
    

    5.其他:copy()和swap()

    copy()方法将string对象或其中的一部分复制到指定的字符串数组中。
    size_t copy (char* s, size_t len, size_t pos = 0) const;
    其中,s指向目标数组,len是要复制的字符数,pos是指从string对象的什么位置开始复制。直到复制了len个字符或到达string对象最后一个字符为止。函数返回复制的字符数。该方法不追加空值字符,也不检查目标数组的长度是否足够。
    swap()交换两个string的内容,函数声明:void swap(basic_string& str)

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值