字符串、向量和数组---C++ 基础
2017-06-06 00:58
211 查看
前言
上一章,复习了基本数据类型,趁热打铁,继续把字符串、向量(vector)和数组搞定。字符串是由字符组成,也是序列结构,因此,本章其实设计到的数据结构是序列。那么就需要考虑是否能够随机访问,如何遍历,如何进行一些基本操作,以及这些基本操作的效率问题。
整个系列的复习会将所有涉及到的stl进行分析,工作量可能会大,但是复习嘛,总是一步一个脚印。废话不多说,开始干货。
3.1 using声明命名空间
命名空间这个东西使得大的项目的名称管理的效率得到了提升。如果需要使用库函数,那么需要加上命名空间才能使用相应的名称。而using就使得不用每个名称前都需要加命名空间。
#include <iostream> using std::cin; // 一般来说,大家都喜欢之间using namespace std,这样就不用对每个对象都使用using了 int main() {}
既然提到了#include,我觉得有必要复习一下预处理器命令,以及宏,这个还是非常重要,我在复习设计模式的,涉及到的一个问题,c++如何实现反射?,详细请见博客另一篇文章《C++反射的实现》
注意:
头文件里不应该包含using声明,因为,头文件的内容会拷贝到所有引用它的文件中,如果头文件里有某个声明,那么每个使用了这个头文件的文件都会有这个声明,名称污染。。。不知哪听来的
3.2 string类型
此处的string类型是标准库中的string,定义在std命名空间里。导入的头文件是string,而不是string.h,后者是c标准下的字符串数组的库函数集合。
#include <string> // 注意,不是string.h,如果想要使用c下的字符串处理函数,使用后者 using namespace std;
string类型是可变长的字符序列。
初始化
string s1; // 默认初始化,空串 string s2 = s1; // s2 是 s1 的副本 string s2(s1); // 直接初始化 string s3("hiya"); string s3 = "hiya"; // s3 是 字面值的副本 string s4(10, 'c'); // s4 "cccccccccc"
操作
os << s // 写入输出流 is >> s // 从流读出字符串,以空白分隔 getline(is, s) // 从流中读出一行 s.empty() s.size() s s1 + s2 s1 = s2 s1 == s2 s1 != s2 <, <=, >, >= s.push_back(char s) s.pop_back() s.begin() s.end() s.rbegin() s.rend() s.reverse() s.clear() s.back() s.front() s += "hello" s.find(str, pos) // 没找到返回-1, 返回string::size_type类型,保证能够在当前机器上存储string对象大小
注意:
string.size() 返回的是size_type类型,这是一个无符号类型,因此,在比较时要特别注意隐式转换(有符号类型会隐式转换成无符号类型),我们知道找不到返回的是size_t 类型的 -1,这个数其实是可能的最大数。
另外string类型的加法,必须要有一个运算对象是string,(字符串字面值不是字符串string类型)
注意:
s = "hello" + "," + s; // 错误,因为"hello"是一个字符串字面值,不是字符串
处理string对象中的字符
#include <cctype> string s = "hello world"; for (auto &c : s) { // 要修改字符,必须要使用引用 cout << isalnum(c) << endl; tolower(c); } char a = 'a'; isalnum(a); isalpha(a); isdigit(a); isspace(a); tolower(a); toupper(a);
3.3 标准库类型vector
vector是标准库里的一类容器,表示对象的有序集合(不包含引用)。
定义和初始化vector对象
vector其内存占用空间是只增不减,erase和clear都不能减少vector占用的内存。所有内存空间在vector析构的时候回收。
#include <vector> using namespace std; vector<T> v1; vector<T> v2(v1); vector<T> v2 = v1; vector<T> v3(n, val); vector<T> v4(n); vector<T> v5{a, b, c}; vector<T> v5 = {a, b, c}; vector<string> v6 = {10, "1"}; // 十个string对象 vector<int> v7 = {10, 1}; // 两个对象
操作
vector<int > arr; arr.push_back(10); arr.pop_back(); arr.empty(); arr.size(); arr.front(); arr.back(); vector<int> foo(3, 100); foo.swap(bar); // swap 是常数时间复杂度(仅仅交换了指针),因此常常用来清空vector,进行内存释放 for (auto &e : arr) { e = 11; // 可以进行修改,但不要对arr进行添加或者删除 }
前面提到了vector怎样清除内存占用的问题。这里就要用到临时对象以及析构的概念了。
vector<int> arr(100000, 0); ... //建立临时对象,然后调用swap函数,临时对象会立即调用析构函数,进行内存释放 vector<int>().swap(arr); a.pop_back(); vector<int>(arr).swap(arr); // 释放一个
注意:
vector 使用下标访问元素,必须是已经存在的下标,不要放低级错误
3.4 迭代器介绍
迭代器在标准库中是一种访问容器对象更加通用的方式,只有少数几个容器是支持下标访问的,目前已知的有vector、string、deque、map、unordered_map。
使用迭代器
auto b = v.begin(); auto e = v.end(); // 记住auto的方法,非常简便,不用写过多的类型 *iter // 返回对象引用 iter -> mem // 取名为mem的成员 ++ iter -- iter iter1 == iter2 iter1 != iter2
注意:
再次提醒,任何改变容器对象数量,都会使得迭代器失效
迭代器运算
iter + n iter - n iter += n iter -= n iter1 - iter2 >, >=, <, <= auto mid = vi.begin() + v.size() / 2; // 取中点
3.5 数组
数组类似vector,但是数组的大小在定义时就已经确定了。
注意:
数组不允许使用 auto 关键字由初始化列表来推断类型
定义和初始化
int a[10]; // 默认初始化 // 显示初始化 int arr[5] = {1, 1}; // 1 1 0 0 0 int arr[] = {1, 1} // 1 1 int arr[2] = {1, 2, 3} // 错误,初始值过多 int arr[100] = {0} // 0 ... // 字符数组,特殊在最后的空字符 char a1[] = {'a', 'b', 'c'} // 最后没有空字符 char a2[] = {'a', '\0'} // 最后有显示的空字符 char a3[] = "hello"; // 自动添加末尾空字符 char a4[5] = "hello word" // 错误,没有空间存放空字符
理解复杂数组
int &ref[10] = ptr; // 错误,没有引用数组 int *ptr[10]; // ptr是一个数组,包含10个int *类型指针的数组 int (*ptr)[10]; // ptr是一个指针,指向含有10个int类型整数的数组 int (&ptr_ref)[10]; // ptr_ref是一个引用,绑定的是含有10个int类型整数的数组
C 风格字符串(安全风险,需要自己管理大小)
C 风格的字符串要求字符串数组要以空字符’\0’结尾。
#include <string.h> strlen(p); strcmp(p1, p2); // 返回比较值,+、-、0 strcat(p1, p2); // p2 附加到p1 ,返回p1 strcpy(p1, p2); // p2 拷贝给p1,返回p1
3.6 多维数组
严格来说,c++没有多维数组,通常说的多维数组都是数组的数组。因此,初始化、访问时都可以仔细理解一下。
int ia[3][4]; // 默认初始化,大小为3的数组,每个元素是4个整数的数组 int arr[100][200] = {0} // 初始化为0 int ia[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10 , 11} }; // 等价于 int ia[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; // 显示初始化每行首元素 int ia[3][4] = {{0}, {3}, {4}}; // 显示初始化第一行,其他的值初始化 int ia[3][4] = {0, 3, 6, 9};
指针和多维数组
时刻记住,多维数组实际上是数组的数组。
int ia[3][4]; int (*p)[4] = ia; // p 指向第一行的数组 p = &ia[2]; // p 指向ia的末尾行 // 值得注意的是,p是一个指向有四个整数的数组的指针,而数组ia就是一个指针,因此p是一个指针的指针 // 比如要找ia[1][1] *(*(ia + 1) + 1); *(ia[1] + 1); *(&ia[0][0] + 4 * 1 + 1); a // 等价于a[0],保存的是指向第一行的数组的指针, 也就是a[0][0] a + 1 // 等价于a[1], 保存的是指向第二行的数组的指针, 也就是a[1][0]
可以使用typedef和using简化多维数组的指针
using int_array = int[4]; typedef int int_array[4];
相关文章推荐
- C++基础(3) —字符串,向量,数组
- C++ 基础(三) —— 字符串、向量和数组
- [C++ 面试基础知识总结]字符串,向量和数组
- C++ Primer 学习笔记(第三章:字符串、向量和数组)
- C++基础教程 学习笔记(二) 数组、字符串和指针
- 【C++基础】 指针&字符串&数组
- C++学习笔记三:字符串、向量和数组
- C++基础之字符数组和字符串
- C++基础之字符数组和字符串
- Unix/Linux C++应用开发-C++基础概念"数组、指针和字符串"
- C++字符串、向量和数组笔记
- C++基础概念-数组、指针和字符串
- java基础改学C++(五)数组(2)字符串
- C++字符串向量和数组
- 【c++语言基础】字符串数组与字符串
- C++Primer第五版 第3章 字符串、向量和数组(练习解答)
- C++学习笔记 | 第三章 字符串、向量和数组 | (1)
- C/C++基础知识总结——数组、指针域、字符串
- C\C++ 程序员从零开始学习Android - 个人学习笔记(四) - java基础 - 数据类型、变量、字符串、数组
- C/C++——字符串和字符数组