第3章 字符串、向量和数组

string表示可变长的字符序列

vector存放的是某种给定类型对象的可变长序列

使用命名空间

using namespace std;

头文件不应包含using声明

1. 标准库类型string

字符串初始化

string s1;
string s2(s1);
string s3("values"); //直接初始化
string s3 = "values"; //拷贝初始化
string s4(n, 'c'); //n个c组成字符串 直接初始化

拷贝初始化和直接初始化

使用等号初始化一个变量叫做拷贝初始化

不使用等号则是直接初始化

string s8 = string(10, 'c');   //拷贝初始化

【C++ Primer】第3章:字符串、向量和数组_数组

在执行读写操作时,string对象会自动忽略开头的空白(即空格符、换行符、制表符等)并从第一个真正的字符开始读写,知道遇见下一个空白为止。

遇到第一个非空白符开始,之后再遇到空白符就结束

例如输入’ Hello World! ‘,会输出’Hello’

int main(){
string s;
cin >> s; // " Hello World "
cout << s <<endl; // "Hello"
return 0;
}
string s1, s2;
cin >> s1 >> s2; // " Hello" " World!"
cout << s1 << s2 <<endl; // "HelloWorld!"

一次读入一个单词

int main(){
string word;
while(cin >> word){
cout << word <<endl;
}
return 0;
}

一次读入一整行

getline函数的参数是一个输入流和一个string对象。

函数从给定的输入流中读入内容,直到遇到换行符为止(注意换行符也被读进来了),然后把所读的内容存入到那个string对象中去(注意不存放换行符)。

int main(){
string line;
while(getline(cin, line)){
cout << line << endl;
}
return 0;
}

​string::size_type​​类型,它是一个无符号类型

auto len = line.size();   //len的类型是string::size_type类型

注意:字符串字面值不能相加,string能相加

切记:字符串字面值与string是不相同的类型

【C++ Primer】第3章:字符串、向量和数组_数组_02

范围for

C++11新标准

for(auto ch : str){
cout << ch << endl;
}

范围for还可以改变字符串中的字符

string s("Hello World!!!");
for(auto &c : s){
c = toupper(c);
}
cout << s <<endl; // "HELLO WORLD!!!"

2. 标准库类型vector

vector是一个类模板

使用模板时,需要指出编译器应把类或函数​​实例化​​成何种类型。

不存在包含引用的vector,因为引用非对象。

【C++ Primer】第3章:字符串、向量和数组_开发语言_03

列表初始化时C++11新标准

vector<string> v{10};       //10个“”
vector<string> v{10, "hi"} //10个"hi"

【C++ Primer】第3章:字符串、向量和数组_c++_04

迭代器

auto b = v.begin();  //b表示v的第一个元素
auto e = v.end(); //e表示v尾元素的下一个位置 //b,e类型相同

​尾后迭代器​​是容器中不存在的位置

特殊情况下如果容器为空,则begin和end返回的是同一个迭代器

所有标准库容器都可以使用迭代器,只有少数容器支持下标运算符

【C++ Primer】第3章:字符串、向量和数组_后端_05

vector<int>::iterator it;   //能读写
string::iterator it2; //能读写

vector<int>::const_iterator it3; //只读不写
string::const_iterator it4; //只读不写

C++11新标准引入cbegin和cend

auto it3 = v.cbegin();  //it3的类型是vector<int>::const_iterator

【C++ Primer】第3章:字符串、向量和数组_数组_06

迭代器的距离类型:​​difference_type​

用迭代器实现二分查找

auto beg = text.begin(), end = text.end();
auto mid = text.begin + (text.end - text.begin())/2;

while(mid!=end && *mid!=target){
if(target < * mid){
end = mid;
}
else
beg = mid + 1;
mid = beg + (end - beg)/2;
}

3. 数组

数组维度编译的时候已知,是一个常量表达式

默认情况下,数组的元素被默认初始化

不能将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值

char a1[] = {'C', '+', '+'};       //维度是3
char a2[] = {'C', '+', '+', '\0'} //维度4
char a3[] = "C++"; //维度4
const char a4[6] = "Daniel"; //错误,没有空间可存放空字符

从右向左,从内向外

int *ptrs[10];             //ptrs是含有10个整型指针的数组
int &refs[10] = arr; //错误:不存在引用的数组
int (*Parray)[10] = &arr; //Parray指向一个含有10个整型的数组
int (&arrRef)[10] = arr; //arrRef引用一个含有10个整型的数组

int *(&array)[10] = ptrs; //array是数组的引用,该数组含有10个指针

使用数组下标的时候,通常将其定义为size_t类型,是无符号整型

指针也是迭代器

c++11新标准引入了begin和end函数

int ia[] = {0,1,2,3,4,5,6,7,8,9};
int *beg = begin(ia); //指向ia首元素的指针
int *last = end(ia); //指向arr尾元素的下一个位置的指针
auto n = end(arr) - begin(arr);  //n的值是5,即arr元素个数   是ptrdiff_t类型  距离可能为负,所以是带符号类型

​size_t和ptrdiff_t​​​都是定义在​​cstddef​​头文件中的机器相关的类型。

C风格字符串

定义在​​cstring​​头文件中

【C++ Primer】第3章:字符串、向量和数组_后端_07

与旧代码的接口

不能用string对象直接初始化指向字符的指针,为了完成功能,string专门提供了一个名为c_str的成员函数

char *str = s;  //错误:不能用string对象初始化char*
const char *str = s.c_str(); //正确

不允许用数组初始化数组

不允许用vector对象初始化数组

可以使用数组初始化vector对象

int int_arr[] = {0,1,2,3,4,5};
vector<int> ivec(begin(int_arr), end(int_arr));

vector<int> subVec(int_arr+1, int_arr+4); //用数组的一部分初始化vector

多维数组

int ia[3][4];
size_t cnt = 0;
for (auto& row : ia) {
for (auto& col : row) {
col = cnt;
++cnt;
}
}
for (const auto& row : ia) {   //&不能少
for (auto col : row) {
cout << col << endl;
}
}

指针和多维数组

for(auto p = ia; p != ia + 3; ++p){      //p的类型是指向4个整数的数组的指针
for(auto q = *p; q != *p +4; ++q){ //q的类型是指向整数的指针
cout << *q << ' ';
}
cout << endl;
}
for(auto p = begin(ia); p != end(ia); ++p){
for(auto q = begin(*p); q != end(*p); ++q){
cout << *q << ' ';
}
cout << endl;
}
using int_array = int[4];
typedef int int_array[4]; //两句功能一样

for(int_array *p = ia; p != ia + 3; ++p){
for(int *q = *p; q != *p +4; ++q){
cout << *q << ' ';
}
cout << endl;
}