目录
string 的 size ()操作 和 string::size_type 类型
使用string对象之前,要在代码头部加上
#include <string> 和using namespace std::string;
(使用命名空间中的名字之前应该用using 声明引入该名字,但是注意using 声明不要放在头文件中,以避免使用了该头文件的文件中会产生名字冲突)。
初始化 string 对象的方式
string s1; // 默认构造函数,s1为空串
string s2(s1); //将s2初始化为s1的一个副本, 叫做直接初始化
string s2 = s1; //等价于string s2(s1),拷贝初始化
string s3("value"); //s3是字面值"value"的副本,除了字面值最后的那个空字符外
string s4(n,'c'); //把s4初始化为由连续n个字符c组成的串
string s5 = string(n,'c'); //拷贝初始化方式, 不建议这样初始化
string 对象的操作
getline( is ,s7,'a'); 一个直到‘a’结束,其中任何字符包括'\n'都能够读入.
cin 和 getline 读写 string对象
int main()
{
string s;
cin >> s;
cout << "输出为:" << s << endl;
system("pause");
return 0;
}
输出结果为:
hello world
输出为:hello
在执行读取操作时, string对象会自动忽略开头的空白(即空格符、换行符、制表符等)并从第一个真正的字符开始读起,直到遇见下一处空白为止。
和内置类型的输入输出操作一样, string对象的此类操作也是返回运算符左侧的运算对象作为其结果。因此,多个输入或者多个输出可以连写在一起。
有时我们希望能在最终得到的字符串中保留输入时的空白符,这时应该用getline函数代替原来的 >>运算符。getline函数的参数是一个输入流和一个string对象, 函数从给定的输入流中读入内容, 直到遇到换行符为止(注意换行符也被读进来了), 然后把所读的内容存入到那个string对象中去 (注意不存换行符), getline只要一遇到换行符就结束读取操作并返回结果, 哪怕输入的一开始就是换行符也是如此。如果输入真的一开始就是换行符,那么所得的结果是个空string.
int main()
{
string str1;
string str2("the size of ");
string str3 = " hello world ";//空格不会忽略
str3 += str2;
str3.append("haha secessful");
cout << "输出str3 的结果:"<< str3 << endl;
cout << "str2 的大小是 " << str2.size() << endl;
/*注意这里取长度的str2.size(),和str2.length(),但是注意str2.size()返回的值并不是int类型,
事实表明size_type存储的string长度是int所能存储的两倍*/
cout << "输入一个字符串:";
getline(cin, str1);
while (!str1.empty()) //返回一个bool值,空的话返回true,否则返回false。
{
for (string::size_type i = 0; i != str1.size(); ++i) //注意size_type类型
{
cout << str1[i];
}
cout << endl; break;
}
system("pause");
return 0;
}
输出结果为:
输出str3 的结果: hello world the size of haha secessful
str2 的大小是 12
输入一个字符串:huang cheng tao
huang cheng tao
注意: 触发getline函数返回的那个换行符实际上被丢弃掉了, 得到的string对象中并不包含该换行符。
string 的 size ()操作 和 string::size_type 类型
该函数返回string对象中字符的个数,计算的时候每个字符都会包含在内,包括空格,string对象还包含 一个成员函数length(),同size()一样,该函数返回string对象中的字符个数,因此在含此类型的表达式中不要使用int.(此时int会转换为unsigned int,可能会带来非预期想要的运算结果)。
● size() 函数返回的是一个 string::size_type 类型的值, 在具体使用的时候, 通过作用域操作符来表明 size_type 是在类 string 中定义的。
● string::size_type 类型 是一个无符号类型的值, 而且能足够存放任何string 对象的大小, 所有用于存放string类 的 size 函数返回值的变量, 都应该是 string::size_type 类型 的。
● 允许编译器通过 auto 或者 decltype 来推断变量的类型:
auto len = line.size() // len的类型是string::size_type 类型
● 由于 size函数返回的是一个无符号整型数, 注意 : 如果在表达式中混用了带符号数和无符号数将可能产生意想不到的结果,
假设n是一个具有负值的int, 则表达式 s. zize() < n的判断结果几乎肯定是 true, 这是因为负值n 会自动地转换成一个比较大的无符号值。
建议 : 如果一条表达式中已经有了 size () 函数就不要再使用 int了, 这样可以避免混用 int 和 unsigned 可能带来的问题。
比较string对象
● 这些比较运算符逐一比较string对象中的字符,并且对大小写敏感,也就是说,在比较时同一个字母的大写形式和小写形式是不同的。
比较的规则是:
- 如果两个string对象的长度不同,而且较短string对象的每个字符都与较长string对象对应位置上的字符相同,就说较短string对象小于较长string对象。
- 如果两个string对象在某些对应的位置上不一致,则string对象比较的结果其实是string对象中第一对相异字符比较的结果。
注意: 按照英文字母的顺序排列, 字母靠前越小,靠后越大。 同一个字母 小写字母比大写字母大。
两个string对象相加
● 两个string对象相加得到一个新的string对象,其内容是把左侧的运算对象与右则的运算对象串接而成。也就是说对string对象使用加法运算符(+)的结果是一个新的string对象,它所包含的字符由两部分组成:
前半部分是加号左侧string对象所含的字符、后半部分是加号右侧string对象所含的字符。另外,复合赋值运算符(+=)负责把右侧string对象的内容追加到左侧string对象的后面。
int main()
{
string str = "huang";
string str1 = "cheng";
cout << "输出结果为:" << (str + str1) << endl;
system("pause");
return 0;
}
输出结果为:
输出结果为:huangcheng
字面值和string对象相加
● 因为标准库允许把字符字面值和字符串字面值 转换成string对象,所以在需要string对象的地方就可以用这两种字面值来代替。
● 当把string对象和字符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符 的两侧运算对象至少有一个string对象:
int main()
{
string str = "huang";
string str1 = "cheng";
string str2 = str + "," + str1 + '\n';
string str3 = str1 + ",";
string str4 = "hello" + ","; //错误
string str5 = str1 + "," + "hello";
string str6 = "huang" + "," + str1; //错误,不能把字面值直接相加
system("pause");
return 0;
}
● 注意:c++语言中的字符串字面值并不是标准库类型 string 的对象, 切记, 字符串字面值与string是不同的类型 。
处理string对象中的字符
● 我们经常需要单独处理string对象中的字符,比如检查一个string对象是否包含空白, 或者把string对象中的字母改成小写,再或者查看某个特定的字符是否出现等。
这类处理的一个关键问题是如何获取字符本身。有时需要处理string对象中的每一个字符,另外一些时候则只需处理某个特定的字符,还有些时候遇到某个条件处理就要停下来。
● 在头文件 cctype 中定义了一组标准库函数处理上述的工作:
处理每个字符? 使用基于范围的for语句
int main()
{
string s("huang cheng tao!!!!");
decltype(s.size()) punct_cnt = 0; //punct_cnt 的类型就是s.size()的返回类型,也就是 string::size_type
// 统计s中标点符号的个数
for (auto c : s)
{
if (ispunct(c)) //对于s中的每个字符,如果该字符是标点符号,计数值加1
++punct_cnt;
}
cout << "s中的标点符号的个数为:" << punct_cnt << endl;
system("pause");
return 0;
}
输出结果为:
s中的标点符号的个数为:3
使用范围for语句改变字符串中的字符
● 如果想要改变 string 对象中字符的值, 必须把循环变量定义成引用类型。当使用引用作为循环控制变量时,这个变量实际上被依次绑定到了序列的每个元素上。 使用这个引用,我们就能改变它绑定的字符。
int main()
{
string s("huang cheng tao!!!");
// 把每一个字符转换成大写形式
for (auto &c : s)
{
c = toupper(c);
}
cout << "s中的字符转换成大写形式为" << s << endl;
system("pause");
return 0;
}
输出结果为:
s中的字符转换成大写形式为HUANG CHENG TAO!!!
每次迭代时, 变量c引用string对象s的下一个字符,赋值给c也就是在改变s中对应字符的值。因此当执行下面的语句时,
c = toupper(c); //c是一个引用,因此赋值语句将改变s中字符的值
实际上改变了c绑定的字符的值。整个循环结束后, str中的所有字符都变成了大写形式。
使用下标和迭代器访问string对象
● 要想访问string对象中的单个字符有两种方式: 一种是 使用下标, 另一种是使用迭代器。
● 下标运算符 [ ] 接收的输入参数是 string::sizee_type 类型的值,这个参数表示要访问的字符的位置; 返回值是该位置上字符的引用。
● 注意 : s[s.size()-1] 是最后一个字符。
● 注意 : string 对象的下标值必须 大于等于0而小于 s.size(), 使用超过此范围的下标将引发不可预知的结果, 以此推断, 使用下标访问空string 也会引发不可预知的结果。
● 注意:下标的值称作“索引”或者 “ 下标”, 任何表达式只要它的值是一个整型值就能作为索引, 不过, 如果某个索引是带符号类型的值将被自动转换成由 string::size_type 表达的无符号类型的值。
● 注意: 不管什么时候只要对string对象使用了下标, 都要确认在那个位置上确实有值。
if(!s.empty()) // 确保确实有字符需要输出 cout<<s[0]<<endl;
● 只要字符串不是常量, 就能为下标运算符返回的字符赋新值。
int main()
{
string s("huang cheng tao!!!");
if (!s.empty())
{
s[0] = toupper(s[0]); // 为s 的第一个字符赋一个新值
}
cout << "输出s的值:" << s << endl;
system("pause");
return 0;
}
输出结果为:
输出s的值:Huang cheng tao!!!
● 另一个列子是把s中的第一个单词该成大写形式:
int main()
{
string s("huang cheng tao!!!");
for (decltype(s.size()) index = 0; index != s.size() && !isspace(s[index]); ++index)
{
s[index] = toupper(s[index]); //每次循环把当前的字符改成大写形式
}
cout << "输出s的值:" << s << endl;
system("pause");
return 0;
}
输出结果为:
输出s的值:HUANG cheng tao!!!
● 其实,也能通过计算得到某个下标值,然后直接获取对应位置的字符,并不是每次都得从前往后依次访问。