C++ Primer Chapter 3 Strings, Vectors, and Arrays
3.1 命名空间的using声明
using声明(using declaration) 具有以下形式
using namespace::name;
每个名字都需要独立的using声明
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main() {
cout << "Enter two numbers:" << endl;
int v1, v2;
cin >> v1 >> v2;
cout << "The sum of " << v1 << " and " << v2 << " is " << v1 + v2 << endl;
return 0;
}
头文件不应包含using声明
3.2 标准库类型string
标准库可行string表示可变长的字符序列,使用string类型必须首先包含string头文件。作为标准库的一部分,string定义在命名空间std中。
#include <sting>
using namespace std::string;
3.2.1 定义和初始化string对象
表3.1:初始化string对象的方式
string s1 | 默认初始化,s1是一个空串 |
string s2(s1) | s2是s1的副本 |
string s3(“value”) | s3是字面值“value”的副本,除了字面值最后的那个空字符外 |
string s3=“value” | 等价于s3(“value”),s3是字面值“value”的副本 |
string s4(n,'c) | 把s4初始化由连续n哥字符c组成的串 |
直接初始化和拷贝初始化
拷贝初始化(copy initialization)
直接初始化(direct initialization)
string s5="hiya"; //拷贝初始化
string s6("hiya"); //直接初始化
string s7(7,'c'); //直接初始化,s7的内容是cccccccc
3.2.2 string对象上的操作**
表3.2 string的操作
os<<s | 将s写到输出流os当中,返回os |
is>>s | 从is中读取字符串赋给s,字符串以空白分隔,返回is |
getline(is,s) | 从is中读取一行赋给s,返回is |
s.empty() | s为空返回true,否则返回false |
s.size() | 返回s中字符的个数 |
s[n] | 返回s中第n哥字符的引用,位置n从0计起 |
s1+s2 | 返回s1和s2连接后的结果 |
s1=s2 | s2的副本代替s1中原来的字符 |
s1==s2 | 如果s1和s2中所含的字符完全一样;string对象的相等性判断对字母的大小写敏感 |
<, <=, >, >= | 利用字符在字典中的顺序进行比较,且对字母的大小写敏感 |
读写string对象
#include <string>
#include <iostream>
using std::string;
using std::cin;
using std::cout;
int main() {
string s;
cin >> s;
cout << s;
system("pause");
}
-------------
### INPUT
hello world
### OUTPUT
hello
使用范围for语句改变字符串中的字符
如果想要改变string对象中的字符的值,必须把循环变量定义成引用类型。
把字符串改写成大写字母
未将循环变量定义为引用类型
void ToUpper() {
string s("Hello World!!!");
for (auto c : s)
{
c = toupper(c);
}
cout << s << endl;
}
### OUTPUT
Hello World!!!
将循环变量定义为引用类型
void ToUpper() {
string s("Hello World!!!");
for (auto &c : s)
{
c = toupper(c);
}
cout << s << endl;
}
### OUTPUT
HELLO WORLD!!!
每次迭代时,变量c引用string对象s的下一个字符,赋值给c也就是在改变s中对应字符的值。
只处理一部分字符
要想访问string对象中的单个字符有两种方式:
▧ 使用下标
▧ 使用迭代器
下标运算符([])接受的输入参数是string::sizetype类型的值,这个参数表示要访问的字符的位置;返回值时该位置上字符的引用。
Note string 对象的下标必须大于等于0小于s.size()。
使用超出此范围的下标将引发不可预知的结果,以此推断,使用下标访问空string也会引发不可预知的结果。
3.3 标准库类型vector
3.3.1 定义和初始化vector对象
C++提供了几种不同的初始化方式。在大多数情况下这些初始化方式可以相互等价地使用,不过也并非一直如此。
目前已经介绍的两种例外情况是:
其一,使用拷贝初始化时(即使用=时),只能提供一个初始值;
其二,如果提供的时一个类内初始值,则只能使用拷贝初始化或使用花括号的形式初始化。
类内初始值(in-class initializer):在声明类得数据成员时同时提供得初始值,必须置于等号右侧或花括号内。
第三种特殊的要求是,如果提供的是初始元素值得列表,则只能把初始值都放在花括号里进行列表初始化,而不能放在圆括号里:
vector<string> v1{"a","an","the"}; //列表初始化
vector<string> v2("a","an","the"); //错误
列表初始化还是元素数量?
vector<int> v1(10); //v1有10个元素,每个的值都是0
vector<int> v2{10}; //v2有一个元素,该元素的值是10
vector<int> v3(10,1); //v3有10个元素,每个的值都是1
vector<int> v4{10,1}; //v4有2个元素,值分别是10和1
如果用的是圆括号,可以说提供的值是用来构造(construct)vector对象的。
如果用的是花括号,可以表述为我们想列表初始化(list initialize)该vector对象。
也就是说,初始化过程尽可能地把花括号内的值当成是元素初始值的列表来处理。只有在无法执行列表初始化时才会考虑其他初始化方式。
另一方面,如果初始化时使用了花括号的形式但是提供的值又不能用来列表初始化,就要考虑用这样的值来构造vector对象了。
vector<string> v5{"hi"}; //列表初始化:v5只有一个元素
vector<string> v6("hi"); //错误:不能使用字符串字面值构建vector对象
vector<string> v7{10}; //v7有10个默认初始值的元素
vector<string> v8{10,"hi"}; //v8有10个值为“hi”的元素
3.3.2 向vector对象中添加元素
向vector对象添加元素蕴含的编程假定
要确保所写的循环正确无误,特别是在循环有可能改变vector对象容量的时候。
如果循环体内部包含有向vector对象添加元素的语句,则不能使用范围for循环。
WARNING 范围for语句体不应该改变其遍历序列的大小。
3.5 数组
数组中元素的个数也属于数组类型的一部分,编译的时候维度应该是已知的。也就是说,维度必须是一个常量表达式。
string strs[get_size()] /当get_size是constexpr时正确;否则错误
和内置类型的变量一样,如果在函数内部定义了某种内置类型的数组,那么默认初始化会令数组元素含有未定义的值。
数组的元素应为对象,因此不存在引用的数组。
字符数组的特殊性
const char a4[6]="Daniel"; //错误:没有空间可存放空字符!
不允许拷贝和赋值
int a[]={0,1,2};
int a2[]=a; //错误:不允许使用一个数组初始化另一个数组
a2=a; //错误:不能把一个数组直接赋值给另一个数组