第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'); //拷贝初始化
在执行读写操作时,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是不相同的类型
范围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++11新标准
vector<string> v{10}; //10个“” vector<string> v{10, "hi"} //10个"hi"
迭代器
auto b = v.begin(); //b表示v的第一个元素 auto e = v.end(); //e表示v尾元素的下一个位置 //b,e类型相同
尾后迭代器
是容器中不存在的位置
特殊情况下如果容器为空,则begin和end返回的是同一个迭代器
所有标准库容器都可以使用迭代器,只有少数容器支持下标运算符
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
迭代器的距离类型: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
头文件中
与旧代码的接口
不能用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; }