C++ 学习笔记(3)命名空间using、字符串、string、vector、迭代器、数组
参考书籍:《C++ Primer 5th》
3.1 命名空间的using声明
- 头文件不应该包含using声明:如果有,那么每个使用了该头文件的文件都会有这个声明,容易造成冲突。
3.2 标准库类型string
3.2.1 定义和初始化string对象
- 直接初始化:使用构造函数。
- 拷贝初始化:使用赋值符号(=)。
3.2.2 string对象上的操作
-
头文件:。在标准命名空间std下。
-
读操作时,string对象会自动忽略开头的空白(空格符、换行符、制表符),从第一个正在字符读起,知道遇到下一处空白为止。
-
使用std::getline()读取一行:直到遇到换行符为止(换行符也读进去了),然后把内如存入string对象中去(换行符不存)。
std::string line; // 字符串
while (getline(std::cin, line)) // 每次读一行,直到文件末端
std::cout<< line << std::endl; // 输出。endl:结束当前行并刷新显示缓冲区
- string::size_type:无符号类型。string::size()的返回值,如果用了这个函数,就不要再使用int,避免混用 int 和 unsigned 可能带来的问题。
3.2.3 处理string对象中的字符
- 使用for循环处理每个字符,如果要修改字符需要把循环变量定义为引用类型。
for (auto &c : s) // 遍历字符串s,每个字符c的引用
c = toupper(c); // 将所有字符转换到大写
3.3 标准库类型vector
3.3.1 定义和初始化vector对象
- 列表初始化:如果确认无法执行列表初始化,编译器会尝试使用默认值初始化vector对象。
vector<int> v1(10); // 10个元素,都为0
vector<int> v2{ 10 }; // 1个元素,为10
vector<int> v3(10, 1); // 10个元素,都为1
vector<int> v4{ 10, 1 }; // 2个元素,为10和1
vector<string> v5("hi"); // 错误!不能使用字符串字面量初始化
vector<string> v6{ "hi" }; // 1个元素,为“hi”
vector<string> v7{ 10 }; // 有10个默认初始化元素(无法使用列表初始化,编译器尝试使用默认值,下同。)
vector<string> v8{ 10, "hi" }; // 有10个值为“hi”的元素
3.3.3 其他vector操作
3.4 迭代器介绍
3.4.1 使用迭代器
- 使用了迭代器的循环体,都不要向迭代器所属容器添加元素(会使迭代器失效)。
- 迭代器都拥有begin和end成员。end表示容器“尾元素的下一个位置(one past the end)”的迭代器,也称尾后迭代器(off-the-end iterator)。如果容器为空,begin和end放回的是同一个迭代器。
- 如果vector或string对象是一个常量,只能使用const iterator。
3.4.2 迭代器运算
- 两个迭代器相减得到的距离:difference_type 的带符号整形数。
3.5 数组
3.5.1 定义和初始化内置数组
unsigend cnt = 42; // 非常量表达式
constexpr unsigned sz = 42; // 常量表达式
int arr[10]; // 含有10个数的数组
int *pass[sz]; // 含有42个整形指针的数组
string bad[cnt]; // 错误:cnt不是常量
string strs[get_size()]; // 当get_size()为constexpr时正确,否则错误
const int& a = 10; // 常引用,还是变量
int b[a]; // 错误:a还是变量
- 数组的元素应为对象,不存在引用的数组。
- 字符数组的结尾包含一个空字符,需要占用字节的。
int *prts[10]; // 含有10个整形指针
int &refs[10]; // 错误:不存在引用的数组
int (*parray)[10] = &arr; // 指针,指向数组
int (&arrRef)[10] = arr; // 引用,数组的引用
int *(&arry)[10] = ptrs; // 数组的引用,该数组含有10个整形指针
3.5.3 指针和数组
- 使用数组的时候,编译器一般会把它转换成指针。
- 在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。
int nums[] = {1, 2, 3};
int *p1 = &nums[0]; // 指针指向nums的第一个元素
int *p2 = nums; // 同上。
auto p3(nums); // p3 的类型是整形指针。
decltype(nums) arr; // arr 的类型是整形数组。
int ia[] = { 1,2,3,4 };
int *beg = begin(ia); // 使用std::begin(),来获取数组的迭代器。
int *last = end(ia);
- 两个指针相减表示距离。名为
ptrdiff_t
的有符号标准库类型。 - 数组的下标,可以是负值。 vector、string下标为无符号类型(size_type)。
3.5.4 C风格字符串
- 一般不负责验证其字符串参数(如:字符串没有以空字符结尾,一些函数使用会报错)。
- 两个C风格字符串上,实际比较的是指针而非字符串本身。(string类型有重载比较符)。
3.5.5 与旧代码的接口
- string::c_str(),将string返回一个C风格字符串,类型是const char *。
- 无法保证c_str函数返回的数组一直有效,如果改变了调用的string对象,会让之前返回的数组失效。想保持原来的数组,可以重新拷贝一份。
3.6 多维数组
int a[3][4] = { {0},{1},{2} }; // 显示初始化每行第一个元素(第一列)
int b[3][4] = { 1,3,5,6 }; // 显示初始化第一行元素
- 要使用for语句处理多维数组时,除了最内层的循环外,其他循环的控制变量都应该是引用类型。
for (auto & row : a) // int (&row)[4],第一维的引用
for (auto & col : row) // int &col,数值的引用,以便修改原始值
col *= 2;
for (auto & row : a) // 同样需要引用,避免数组转换成指针
for (auto col : row) // 不用引用,因为不需要修改原始值
cout << col << endl;
for (auto row : a) // int *row
for (auto col : row) // 错误:无法遍历指针
cout << col << endl;