Strings, Vectors, and Arrays
Namespace using Declarations
A using declaration lets us use a name from a namespace without qualifying the name with a namespace_name:: prefix. A using declaration has the form using namespace::name;
1 | using std::cin; |
Library string Type
1 |
|
初始化 string:
1 | string s1; // default initialization; s1 is the empty string |
直接初始化与拷贝初始化
expression | description |
---|---|
string s1 | Default initialization; s1 is the empty string. |
string s2(s1) | s2 is a copy of s1. |
string s2 = s1 | Equivalent to s2(s1), s2 is a copy of s1. |
string s3(“value”) | s3 is a copy of the string literal, not including the null. |
string s3 = “value” | Equivalent to s3(“value”), s3 is a copy of the string literal. |
string s4(n, ’c’) | Initialize s4 with n copies of the character ’c’. |
Operations on string
expression | description |
---|---|
os << s | Writes s onto output stream os. Returns os. |
is >> s | Reads whitespace-separated string from is into s. Returns is. |
getline(is, s) | Reads a line of input from is into s. Returns is. |
s.empty() | Returns true if s is empty; otherwise returns false. |
s.size() | Returns the number of characters in s. |
s[n] | Returns a reference to the char at position n in s; positions start at 0. |
s1 + s2 | Returns a string that is the concatenation of s1 and s2. |
s1 = s2 | Replaces characters in s1 with a copy of s2. |
s1 == s2 | The strings s1 and s2 are equal if they contain the same characters. |
s1 != s2 | Equality is case-sensitive. |
<, <=, >, >= | Comparisons are case-sensitive and use dictionary ordering. |
The string input operator reads and discards any leading whitespace (e.g., spaces, newlines, tabs). It then reads characters until the next whitespace character is encountered.
用 cin 读取输入流,向 string 中写入内容时,会消费并丢弃输入流开头的空格(也包括换行、Tab),只要输入流中的当前字符不是空白,就读取它,直到遇到第一个空白,这个空白不会被消费。
读取未知个数的字符串:
1 | int main() |
The getline function takes an input stream and a string. This function reads the given stream up to and including the first newline and stores what it read—not including the newline—in its string argument. After getline sees a newline, even if it is the first character in the input, it stops reading and returns. If the first character in the input is a newline, then the resulting string is the empty string.
如果不想忽略输入中的空白字符,可以用 getline
,能够一直读取,直到遇到换行符。输入流中的换行符会被读取,然后被丢弃,不会被存入 getline
第二个变量中。只读 \n
,不存 \n
:
1 | int main() |
s.size()
的类型是 string::size_type
,是一个无符号整数,利用自定义类型是为了做到与机器平台无关。
不能相加两个字符字面量,string 对象和字面量混用时,每个加号左右至少要有一个 string 对象:
When we mix strings and string or character literals, at least one operand to each +
operator must be of string type:
1 | string s4 = s1 + ", "; // ok: adding a string and a literal |
C++ 中,头文件尽量用 cname 而不是 name.h
In particular, the names defined in the cname headers are defined inside the std namespace, whereas those defined in the .h versions are not.
range-for statement
1 | for (declaration : expression) |
On each iteration, the next character in str will be copied into c.
1 | string s1 = "123"; |
Using a Range for to Change the Characters in a string
If we want to change the value of the characters in a string, wemust define the loop variable as a reference type.
1 | string s("Hello World!!!"); |
On each iteration, c refers to the next character in s.
Library vector Type
expression | description |
---|---|
vector |
v1 vector that holds objects of type T. Default initialization;v1 is empty. |
vector |
v2(v1) v2 has a copy of each element in v1. |
vector |
v2 = v1 Equivalent to v2(v1), v2 is a copy of the elements in v1. |
vector |
v3(n, val) v3 has n elements with value val. |
vector |
v4(n) v4 has n copies of a value-initialized object. |
vector |
v5{a,b,c . . .} v5 has as many elements as there are initializers; elements are initialized by corresponding initializers. |
vector |
v5 = {a,b,c . . . } Equivalent to v5{a,b,c . . . }. |
When we use parentheses, we are saying that the values we supply are to be used to construct the object.
When we use curly braces, {…}, we’re saying that, if possible, we want to list initialize the object. That is, if there is a way to use the values inside the curly braces as a list of element initializers, the class will do so. Only if it is not possible to list initialize the object will the other ways to initialize the object be considered.
使用大括号的时候,编译器会检查能否用大括号的内容做列表初始化,如果不能,编译器将会用里面的值作为构造参数来构建对象。换句话说,写到大括号里的内容,不一定全部都被当做列表初始化,也可能会被当做构造参数。
1 | vector<string> v5{"hi"}; // list initialization: v5 has one element |
expression | description |
---|---|
v.empty() | Returns true if v is empty; otherwise returns false. |
v.size() | Returns the number of elements in v. |
v.push_back(t) | Adds an element with value t to end of v. |
v[n] | Returns a reference to the element at position n in v. |
v1 = v2 | Replaces the elements in v1 with a copy of the elements in v2. |
v1 = {a,b,c . . . } | Replaces the elements in v1 with a copy of the elements in the comma-separated list. |
v1 == v2 | v1 and v2 are equal if they have the same number of elements and each |
v1 != v2 | element in v1 is equal to the corresponding element in v2. |
<, <=, >, >= | Have their normal meanings using dictionary ordering. |
The subscript operator on vector (and string) fetches an existing element; it does not add an element.
迭代器
大多数迭代器没有定义比较运算符,只有 = 和 !=
迭代器使用 ++
从一个元素移动到下一个元素
我们可以对迭代器解除引用,获取迭代器指示元素的值
As with pointers, an iteratormay be valid or invalid. A valid iterator either denotes an element or denotes a position one past the last element in a container. All other iterator values are invalid.
Types that have iterators have members that return iterators. In particular, these types have members named begin and end.
1 | // the compiler determines the type of b and e; see § 2.5.2 (p. 68) |
The iterator returned by end is an iterator positioned “one past the end” of the associated container (or string).
The iterator returned by end is often referred to as the off-the-end iterator or abbreviated as “the end iterator.”
We can compare two valid iterators using == or !=. Iterators are equal if they denote the same element or if they are both off-the-end iterators for the same container. Otherwise, they are unequal.
如果两个迭代器知识的元素相同,或者都指向 off-the-end,这两个迭代器相等,其他情况他们不相等。
The library types that have iterators define types named iterator and const_iterator that represent actual iterator types:
1 | vector<int>::iterator it; // it can read and write vector<int> elements |
如果一个容器对象是常量,那么通过 v.begin()
和 v.end()
获取到的迭代器也是 const_iterator
。
还可以通过 v.cbegin()
和 v.cend()
显示获取常量迭代器。
常量迭代器只能读取不能修改所指示的内容。
使用迭代器的循环里面不要改变容器的大小,否则会造成迭代器失效。
解除引用并访问成员
(*it).empty()
注意需要括号。
Iterator Arithmetic
可以对两个迭代器做减法,返回的是两个迭代器之间的距离,类型是 difference_type
。This type is signed, because subtraction might have a negative result.
Arrays
Arrays have fixed size; we cannot add elements to an array.
Performance is better.
Defining and Initializing Built-in Arrays
An array declarator has the form a[d]
.
The number of elements in an array is part of the array’s type.
As a result, the dimension must be known at compile time, which means that the dimension must be a constant expression.
As with vector, arrays hold objects. Thus, there are no arrays of references.
Explicitly Initializing Array Elements
If we omit the dimension, the compiler infers it from the number of initializers.
If we specify a dimension, the number of initializers must not exceed the specified size.
If the dimension is greater than the number of initializers, the initializers are used for the first elements and any remaining elements are value initialized.
Character Arrays are Special
Character arrays have an additional form of initialization: We can initialize such arrays from a string literal.
string literal ends with a null character.
1 | char a1[] = {’C’, ’+’, ’+’}; // list initialization, no null |
No Copy or Assignment
We cannot initialize an array as a copy of another array, nor is it legal to assign one array to another:
1 | int a[] = {0, 1, 2}; // array of three ints |