主题 : 《Thinking in C++》标准c++中string类介绍
取我所需的坦荡,即使病入膏肓
级别: 五分秋意
UID: 76075
精华: 0
发帖: 1382
威望: 4765 点
无痕币: 4174 WHB
贡献值: 2 点
在线时间: 148(时)
注册时间: 2009-01-01
最后登录: 2018-01-24

0 《Thinking in C++》标准c++中string类介绍

这几天看了Bruce所著《Thinking in C++》一书中有关string类的介绍,结合之前收集到的一些相关资料,这里做个系统的总结,希望能和大家在C++的大路上共同前行。
在C语言中,字符串基本就是字符型数组,并且总是以二进制零(即空结束付)作为其最末元素。C++ string类与它们在C语言中的前身截然不同,C++ string类具有很多优点:

1>. 隐藏了字符串序列内部字符序列的物理表示:也就是说程序设计人员不必关心数组维数及空结束符问题,例如当程序访问越界时,字符串内部会做自动抛出异常等处理,而不用程序去检测是否遇到空结束符,这很大程度上隐藏了一些复杂的实现,更方便程序员使用。
2>. 无需程序员干预,string类可以根据需要自动扩充规模:在C中,当对字符串操作时,通常需要程序员跟踪字符串的存储边界,当对一个对象扩充时,需要程序员手动扩充存储,同时,这些令人生厌的“内务处理”琐事不仅不方便,而且不安全,C++中的string类则解决了这些问题,使用C++时会最真切的感 受到这些。
3>. 提高了便利性和安全性:在C语言中,为了实现对字符串方便的操作,提供了一系列库函数,然而但这些库函数名列表不仅冗长,而且充满了模糊不清、晦涩难懂的名字;C++通过理性化的命名机制、函数重载及默认参数解决了这些问题。

下面将从以下四方面做更详细的介绍:
1. 创建并初始化字符串
2. 字符串操作
3 字符串比较
4 其他常用函数介绍

1. 创建并初始化字符串

创建并初始化字符串至少有如下9种方法:
======================================================================================
string s; 生成一个空字符串s,并不立即初始化它

string s(“string”); 创建字符串并用引用字符数组进行初始化

string s = str; 采用重载运算符方法,用已有字符串初始化新字符串

string s(str,stridx,strlen); 将字符串str内始于stridx且长度顶多strlen的部分作为字符串的初值,其中str、stridx、strlen的默认值分别为””、0、极大整型值

string s(chars,chars_len); 将C字符串前chars_len个字符作为字符串s的初值,chars_len的默认值为极大整型值

string s(num,c); 生成一个字符串,包含num个c字符

string s(s1.begin(),s1.end()); 采用迭代器方法,选取字符串区间beg-end(不包含end)内的字符作为字符串s的初值

string s = “a”+”b”; 使用operator+链接已有字符串后初始化新字符串
string s = str.substr(stridx,strlen);
使string对象的用成员函数substr()来初始化字符串,其中stridx、strlen的默认值分别为0、极大整型值
======================================================================================

实例1创建并初始化字符串
======================================================================================
#include <string>
#include <iostream>
using namespace std;
int main() {
string s1("What is the sound of one clam napping?");
string s2("Anything worth doing is worth overdoing.");
string s3("I saw Elvis in a UFO");
// Copy the first 8 chars:
string s4(s1, 0, 8);
string str("a new string", 5);
cout << s4 << endl;
// Copy 6 chars from the middle of the source:
string s5(s2, 15, 6);
cout << s5 << endl;
// Copy from middle to end:
string s6(s3, 6, 15);
cout << s6 << endl;
// Copy many different things:
string quoteMe = s4 + "that" +
// substr() copies 10 chars at element 20
s1.substr(20, 10) + s5 +
// substr() copies up to either 100 char
// or eos starting at element 5
"with" + s3.substr(5, 100) +
// OK to copy a single char this way
s1.substr(37, 1);
cout << quoteMe << endl;
} ///:~
======================================================================================

2. 字符串操作

2.1 插入、追加和连接操作(增操作)

======================================================================================
s.insert(stridx, str ); 在指定下标stridx对应的字符前插入字符串str,即执行插入操作

s.append(str); 在指定字符串s后追加给定字符串str,如果存储规模不足,会自动扩展,即执行追加操作

a = a + str; 连接操作由重载运算符实现
===============================================================================

实例2插入、追加和连接操作
======================================================================================
#include <string>
#include <iostream>
using namespace std;
int main() {
string bigNews("I saw Elvis in a UFO. ");
cout << bigNews << endl;
// How much data have we actually got?
cout << "Size = " << bigNews.size() << endl;
// How much can we store without reallocating?
cout << "Capacity = " << bigNews.capacity() << endl;
// Insert this string in bigNews immediately
// before bigNews[1]:
bigNews.insert(1, " thought I");
cout << bigNews << endl;
cout << "Size = " << bigNews.size() << endl;
cout << "Capacity = " << bigNews.capacity() << endl;
// Make sure that there will be this much space
bigNews.reserve(500);
// Add this to the end of the string:
bigNews.append("I've been working too hard.");
cout << bigNews << endl;
cout << "Size = " << bigNews.size() << endl;
cout << "Capacity = " << bigNews.capacity() << endl;
} ///:~
===============================================================================

2.2 从字符串中删除字符(删操作)
===============================================================================
s.erase(stridx, strlen); 删除字符串中的字符,stridx指定删除起始位置,默认值为0strlen表示删除字符序列个数,默认值为极大整型值
======================================================================================

2.3 替换字符串中的字符(改操作)
======================================================================================
s.replace(stridx, strlen, str); 对指定下标开始到指定长度strlen区间的字符序列用字符串str替换
======================================================================================


2.4 字符串的查找(查操作)
======================================================================================
s.find(char|str, stridx); 在指定单词中,从指定下标stridx开始,查找单个字符或字符串: 如果找到,返回首次匹配的开始位置;否则返回string::npos

s. find_first_of(char|str, stridx); 在指定单词中,从指定下标stridx开始,查找第一个与指定字符数组str中任何字符匹配的字符位置: 如果找到,返回第一次匹配的开始位置;否则返回string::npos

s. find_last_of(char|str, stridx); 在指定单词中,从指定下标stridx开始,查找最后一个与指定字符数组str中任何字符匹配的字符位置: 如果找到,返回最后一次匹配的开始位置;否则返回string::npos。功能和find类似

s. find_first_not_of(char|str, stridx); 在指定单词中,从指定下标stridx开始,查找第一个不与指定字符数组str中任何字符匹配的字符位置: 如果找到,返回第一次匹配的开始位置;否则返回string::npos

s. find_last_not_of(char|str, stridx); 在指定单词中,从指定下标stridx开始,查找最后一个不与指定字符数组str中任何字符匹配的字符位置: 如果找到,返回最后一次匹配的开始位置;否则返回string::npos。功能和find类似

s.rfind(char|str, stridx); 在指定单词中,从指定下标stridx开始,反向查找单个字符或字符串: 如果找到,返回首次匹配的开始位置;否则返回string::npos
======================================================================================

实例3:字符串的查找(查操作)
======================================================================================
#ifndef SIEVE_H
#define SIEVE_H
#include <cmath>
#include <cstddef>
#include <string>
#include "../TestSuite/Test.h"
using std::size_t;
using std::sqrt;
using std::string;
class SieveTest : public TestSuite::Test {
string sieveChars;
public:
// Create a 50 char string and set each
// element to 'P' for Prime:
SieveTest() : sieveChars(50, 'P') {}
void run() {
findPrimes();
testPrimes();
}
bool isPrime(int p) {
if(p == 0 || p == 1) return false;
int root = int(sqrt(double(p)));
for(int i = 2; i <= root; ++i)
if(p % i == 0) return false;
return true;
}
void findPrimes() {
// By definition neither 0 nor 1 is prime.
// Change these elements to "N" for Not Prime:
sieveChars.replace(0, 2, "NN");
// Walk through the array:
size_t sieveSize = sieveChars.size();
int root = int(sqrt(double(sieveSize)));
for(int i = 2; i <= root; ++i)
// Find all the multiples:
for(size_t factor = 2; factor * i < sieveSize;
++factor)
sieveChars[factor * i] = 'N';
}
void testPrimes() {
size_t i = sieveChars.find('P');
while(i != string::npos) {
test_(isPrime(i++));
i = sieveChars.find('P', i);
}
i = sieveChars.find_first_not_of('P');
while(i != string::npos) {
test_(!isPrime(i++));
i = sieveChars.find_first_not_of('P', i);
}
}
};
#endif // SIEVE_H ///:~
#include "Sieve.h"
int main() {
SieveTest t;
t.run();
return t.report();
} ///:~
======================================================================================

3 字符串比较

字符串的比较其实是进行字典比较;字典比较的意思是,当测试一个字符看它是否大于另一个字符时,时机比较的是它们的数值表示,而这些数值表示是由当前所使用的字符集的校对序列决定的,通常这种校对序列是ASCII校对序列;当字典比较报告字符串S1大于S2时,也即两者相比较时,字符串S1中第一个不同的字符比字符串S2中同样位置的字符在ASCII表中的位置更靠后。

方法一 运算符重载
C++ string类提供了运算符重载的方法,用于比较字符串;这种方法直观而且使用方便。

实例4 运算符重载
======================================================================================
#ifndef COMPSTR_H
#define COMPSTR_H
#include <string>
#include "../TestSuite/Test.h"
using std::string;
class CompStrTest : public TestSuite::Test {
public:
void run() {
// Strings to compare
string s1("This");
string s2("That");
test_(s1 == s1);
test_(s1 != s2);
test_(s1 > s2);
test_(s1 >= s2);
test_(s1 >= s1);
test_(s2 < s1);
test_(s2 <= s1);
test_(s1 <= s1);
}
};
#endif
#include "CompStr.h"
int main() {
CompStrTest t;
t.run();
return t.report();
} ///:~
======================================================================================

方法二 compare函数
除运算符重载之外,可以利用compare函数进行更复杂精密的比较手段;它提供重载版本,可以比较:
  • 两个完整的字符串: str1.compare(str2);
  • 一个字符串的某一部分和另一个字符串的全部: str1.compare(stridx, strlen, str2);
  • 两个字符串的子串: str1.compare(stridx, strlen, str2, stridx, strlen);
其中,stridx是给定字符串进行比较部分的开始,stdlen是要比较的字符长度。

实例: compare函数
======================================================================================
#include <cassert>
#include <string>
using namespace std;
int main() {
string first("This is a day that will live in infamy");
string second("I don't believe that this is what "
"I signed up for");
// Compare "his is" in both strings:
assert(first.compare(1, 7, second, 22, 7) == 0);
// Compare "his is a" to "his is w":
assert(first.compare(1, 9, second, 22, 9) < 0);
} ///:~
======================================================================================

4 其他常用函数介绍

除了以上介绍到的对字符串的操作,下面对于一些经常用到的几个有意义的函数做如下解释及对比:
======================================================================================
s.size(); 返回当前在字符串中存储的字符数

s.length(); 作用等同于size()成员函数


s.capacity(); 返回为当前字符串分配的存储空间的规模,一般大于size()成员函数的返回值

s.reserve(strlen); 按照程序员的意图,预留指定长度的存储空间,此时capacity()成员函数的返回值与strlen接近:当strlen大于字符串长度时,扩充存储空间;否则不做任何处理

s.resize(strlen); 按照程序员的意图,重定义字符串: 如果strlen长度大于当前字符串长度,则在当前字符串后补空格;否则,则会截取当前字符串。resize对字符串本身操作,而reserve对存储空间操作

s.swap( str); 用于交换两个字符串的内容,参数必须为字符串型变量

s.clear(); 清空指定字符串,删除其中全部字符

s[stridx]; 用于元素存取,但是应该注意的是操作符[]并不检查索引是否有效(有效索引0~str.length()),如果索引失效,会引起未定义的行为

s.at(stridx); 用于元素存取,at()会做正确性检查,如果使用 at()的时候索引无效,会抛出out_of_range异常

s.empty(); 判断字符串是否为空:为空返回true,否则返回false
======================================================================================


以上内容部分来源于《Thinking in C++》,这里总结了一下,拿出来和大家分享,由于编写匆忙,未仔细检查细节错误,可能存在细节问题,如读者发现,请留下评论,以便纠正,十分感谢。
本帖最近评分记录:
  • 无痕币:+50(lvming780910) 楼住辛苦了,感谢分享
  • 级别: 无痕元老

    UID: 8888
    精华: 0
    发帖: 222965
    威望: 322240 点
    无痕币: 53507 WHB
    贡献值: 0 点
    在线时间: 106394(时)
    注册时间: 2008-10-18
    最后登录: 2024-05-02

    不懂啊,程序员看吧
    知足常乐
    级别: 十方秋水

    UID: 23
    精华: 1
    发帖: 261127
    威望: 117140 点
    无痕币: 2371 WHB
    贡献值: 0 点
    在线时间: 9391(时)
    注册时间: 2007-11-24
    最后登录: 2024-05-01

    不懂,回帖支持一下版主。
    事能知足心常乐 人到无求品自高
    我为人人,人人为我
    级别: 七朵秋菊

    UID: 13542
    精华: 0
    发帖: 1211
    威望: 47453 点
    无痕币: 23241 WHB
    贡献值: 0 点
    在线时间: 437(时)
    注册时间: 2008-02-19
    最后登录: 2023-08-15

    收下,慢慢看
    千山同一月 万户尽皆春 千江有水千江月 万里无云万里天
    级别: 总版主

    UID: 998
    精华: 0
    发帖: 605035
    威望: 529375 点
    无痕币: 8 WHB
    贡献值: 0 点
    在线时间: 62285(时)
    注册时间: 2008-12-25
    最后登录: 2024-05-02

    的确要慢慢看的
    Total 0.083511(s) query 4, Time now is:05-02 22:36, Gzip enabled 粤ICP备07514325号-1
    Powered by PHPWind v7.3.2 Certificate Code © 2003-13 秋无痕论坛