参考资料:
- 《C++ Primer》第5版
- 《C++ Primer 习题集》第5版
3.1 命名空间的using
声明(P74)
作用域操作符 ::
表示从左侧名字所示的作用域中寻找右侧名字,因此 std::cin
的意思就是使用命名空间 std
中的 cin
。
为了方便并安全地使用命名空间中的成员,可以使用 using
声明。
每个名字都需要独立的using
声明
using std::cin;
using std::cout;
用到的每个名字必须有自己的声明语句,每条声明语句必须以分号结束。
头文件不应包含using
声明
由于头文件中的内容可能会拷贝到其他文件中,很可能导致名字冲突。
3.2 标准库类型string
(P75)
string
可表示变长的字符序列,定义在命名空间 std
中:
#include<string>
using std::string;
3.2.1 定义和初始化string
对象(P76)
一个类可以定义多种初始化方式,这些方式要么初始值类型不同,要么初始值数量不同。string
类最常见的初始化方式有:
直接初始化和拷贝初始化
使用 =
初始化对象实际上执行的是拷贝初始化,反之则执行的是直接初始化。当初始值只有一个时,两种方法都可以;当初始值有多个时,拷贝初始化必须显式创建一个临时对象用于拷贝:
string s7(10, 'c');
string s8 = string(10, 'c');
3.2.2 string
对象上的操作(P77)
读写string
对象
string s;
cin >> s; // 假设输入“ hello ”
cout >> s; // 输出“hello”
使用 >>
将内容读取到 s
中时,string
对象会自动忽略开头的空白(空格符、换行符、制表符等)并从第一个真正的字符开始读起,直到遇到下一处空白为止。
读取未知数量的string
对象
while(cin>>s){
/* ... */
}
使用getline
读取一整行
如果希望保留输入中的空白符,可以使用 getline
函数。getline
函数的参数是一个输入流和一个 string
对象,函数从输入流中读取内容,直到遇到换行符位置(换行符也被读进来了),然后把读到的内容存入 string
对象中(不存换行符)。getline
的返回值它的流参数,同样可用于条件判断:
while(getline(cin, s)){
/* ... */
}
string
的empty
和size
操作
string::size_type
类型
size
函数的返回类型为 string::size_type
。大多数标准库类都定义了几种配套类型,体现了标准库类型与机器无关的特性。
string::size_type
是一个无符号的值,并且足够存下任何 string
对象的大小;任何用于存放 string
类 size
函数返回值的变量都应是 string::size_type
类型:
auto len = s.size();
当表达式中有
size()
时,不要再使用int
比较string
对象
字典序。
为string
对象赋值
string s1, s2("hello");
s1 = s2;
两个string
对象相加
运算结果为两个运算对象的串接。
字面值和string
对象相加
标准库允许把字符字面值和字符串字面值转换成 string
对象。当把 string
对象和字面值混用在一条加法时,必须保证每个 +
两侧至少有一个对象为 string
:
string s("hello");
s = s + "," + "world"; // 正确,第一个加号运算后得到string对象
s = "world" + "," + s; // 错误
为了和 C 语言兼容,C++ 中的字符串字面值不是
string
对象。例如,"hello"
的类型为const char[7]
3.2.3 处理string
对象中的字符(P81)
C++ 兼容了 C 语言的标准库,例如,C 语言存在头文件 name.h ,则 C++ 中对应的头文件为 cname 。需要说明的是,cname 中的名字定义在 std 中,而 name.h 则不然,所以 C++ 程序应该使用 cname 头文件。
处理每个字符?使用基于范围的for
语句
如果想对字符串中的每个字符进行操作,最好的方法是使用范围 for
语句:
for(declaration : expression)
statement
expression
为一个序列对象,declaration
部分负责定义一个变量,用于访问序列中的基础元素。每次迭代,declaration
部分的变量会被初始化为下一个元素值。
每次迭代都对变量进行初始化,应该是为了保证范围
for
语句能使用引用变量。
string s("hello");
for(auto c : s){
cout << c << ' ';
}
这里 auto
推断出的类型为 char
。
使用范围for
语句改变字符串中的字符
想要改变 string
对象的值,必须把范围 for
循环中的变量定义成引用类型:
string s("hello");
for(auto &c : s){
c = toupper(c);
}
只处理一部分字符?
想要访问 string
对象中的单个字符有两种方式:使用下标、使用迭代器。
下标运算符 []
接受的输入参数为 string::size_type
类型,返回值为该位置上字符的引用。string
类型的下标必须大于等于 0
且小于其 size
。
使用下标执行迭代
string s("hello");
// 依次处理s中的字符,知道遇到空格或结尾。
for(decltype(s.size()) index=0;index!=s.size()&&!isspace(s[index]);s++){
s[index] = toupper(s[index]);
}
上面的代码中,&&
运算符只有当左侧为真时才会检查右侧,所以必须先判断 index
的合法性,再对对应的字符进行判断。
使用下标执行随机访问
练习
s[index] = toupper(s[index]);
}
上面的代码中,`&&` 运算符只有当左侧为真时才会检查右侧,所以必须先判断 `index` 的**合法性**,再对对应的字符进行判断。
### 使用下标执行随机访问
### 练习
[外链图片转存中...(img-lnn8ZDjY-1694521712024)]
> 合法,c 为**字符常量的引用**