《C++ Primer》读书笔记—第三章 字符串、向量和数组
声明:
- 文中内容收集整理自《C++ Primer 中文版 (第5版)》,版权归原书所有。
- 学习一门程序设计语言最好的方法就是练习编程
这一部分内容比较简单。
string表示可变长的字符序列,vector存放的是某种给定类型对象的可变长序列。
一、命名空间的using声明
1、using namespace std;
2、头文件不应该包含using声明,因为头文件会被多个源文件引用,有的程序不经意间包含了一些名字,可能与头文件中的内容冲突。
3、理论上每用一个名字using一次比较好,因为不清楚整个命名空间都有哪些关键字,可能造成命名冲突。
二、标准库类型string
1、定义一个名为s的空string,然后执行输入,输出时会自动忽略开头空白,并从第一个字符开始,直到遇到第下一处空白。如“Hello Word”,只会输出“Hello”。
1 int main(){ 2 string s; 3 cin>>s; 4 cout<<s<<endl; 5 6 return 0; 7 }
2、使用getline读取一整行 使用getline代替>>,保留输入中的空白符。
getline的参数是一个输入流和一个string对象,函数从给定的输入流中读取内容,直到换行符为止(换行符也读取进来了)。
1 int main(){ 2 3 string line; 4 while(getline(cin,line)){ 5 cout<<line<<endl; 6 } 7 return 0; 8 }
3、empty函数根据string对象是否为空返回一个对应的布尔值。
size函数返回string对象的长度。size函数的返回值类型是string::size_type,size_type是在类string中定义的,它是一个无符号类型的值。
4、0-15之间的十进制数转换为十六进制。初始化一个字符串令其存放16个十六进制的“数字”
1 int main(){ 2 3 const string hexdigits = "0123456789ABCDEF";//可能的十六进制数字 4 cout<<"Enter a series of numbers between 0 and 15"<<" separated by spaces. Hit ENTER when finished: "<<endl; 5 string result; //保存十六进制的字符串 6 string::size_type n; //用于保存从输入流读取的数 7 while(cin>>n) 8 if(n<hexdigits.size()) //忽略无效输入 9 result+=hexdigits[n]; //得到对应的十六进制 10 cout<<"Your hex number is :"<<result<<endl; 11 12 return 0; 13 }
三、标准库类型vector
1、vector生成的类型必须包含vector中元素的类型,如vector<int>。
2、vector初始化:
1 vector<int> v1( 10 ); //v1有10个元素,每个值为0 2 vector<int> v2{ 10 }; //v2有1个元素,每个值为10 3 vector<int> v3( 10, 1 ); //v3有10个元素,每个值为1 4 vector<int> v4{ 10, 1 };//v1有2个元素,一个为10,一个为1
3、基本操作
(1)头文件#include<vector>.
(2)创建vector对象,vector<int> vec;
(3)尾部插入数字:vec.push_back(a);
(4)使用下标访问元素,cout<<vec[0]<<endl;记住下标是从0开始的。
(5)使用迭代器访问元素.
vector<int>::iterator it; for(it=vec.begin();it!=vec.end();it++) cout<<*it<<endl;
(6)插入元素:vec.insert(vec.begin()+i,a);在第i+1个元素前面插入a;
(7)删除元素:vec.erase(vec.begin()+2);删除第3个元素
vec.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始
(8)向量大小:vec.size();
(9)清空:vec.clear();
4、vector直接初始化适用于三种情况:初始值已知且数量较少、初始值是另一个vector对象的副本、所有元素的初始值都一样。
5、vector能在运行时高效快速的添加元素。因此使用vector比较高效的一种方法就是先定义一个空的vector,再在运行时向其中添加具体值。
6、push_back函数:创建一个空的vector,在运行时向其中添加元素。push_back负责把一个值当成vector的尾元素push到vector对象的尾端。
vector<int>v2;
for(int i = 0;i!=100;++i)
v2.push_back(i);
6、vector对象及string对象下标运算符可用于访问已存在的元素而不能用于添加元素。只能用push_back。
7、来自知乎“诸葛不亮”:现在各大编译器实现的string都有短字符串优化,实现方式是在内部同时持有一个定长char数组和一个char*指针。在字符串数据短时,使用数组存储,这样就可以利用栈内存效率比堆内存高的优势了。内置数组长度各编译器不同,vs好像是24字节?
所以未初始化长度的string,其实至少头几个字节还是有效可用的。
至于何时切换么存储——string内部一般会持有一个uint32之类的数据,用struct+位域拆分为两个变量,最高位0/1标识用数组还是用指针保存内容,后面的位数用来存储数据长度。
四、迭代器介绍
1、迭代器可以用来访问string和vector对象的元素。
尾后迭代器(off-the-end iterator)end函数返回的迭代器,指向一个并不存在的元素,该元素位于容器尾元素的下一位置。
2、迭代器运算:迭代器与整数相加或相减得到一个新的迭代器,与原来的迭代器相比,新的迭代器向前或者向后移动了若干个位置。
3、
auto itrBeg = v.begin();
auto itrEnd = v.end();
- begin函数负责返回指向第一个元素的迭代器
- end函数返回指向尾后元素的迭代器,尾后元素是“尾元素的下一位置”
4、如果对象只需读操作而无需写操作的话最好使用常量类型(如const_iterator)。
5、迭代器相减可以得到两个迭代器指针的距离,即右边的迭代器移动多少个距离可以追上左侧的迭代器。得到的距离类型为difference_type,是带符号整型,这个距离可正可负。
6、使用迭代器实现二分搜索。从有序序列中找出某个给定的值。
1 //test必须是有序的 2 //beg和end表示我们的搜索范围 3 auto beg = text.begin(), end = text.end(); 4 auto mid = beg + ( end - beg ) / 2; 5 while( mid != end && *mid != target) 6 { 7 if( target < *mid ) 8 { 9 end = mid; //如果要找的元素在前半部分,则搜索范围忽略后部分 10 } 11 else 12 { 13 beg = mid + 1; //mid之后寻找 14 } 15 16 mid = beg + ( end - beg ) / 2;//新的中间点 17 }
五、数组
1、和vector一样,数组可以存放大多数的对象。例如,可以定义一个存放指针的数组。数组本身也是对象,允许定义数组的指针及数组的引用。
2、理解数组声明的含义,最好的方法是从数组名字开始由内向外的顺序阅读。
如:
int *ptrs[10] //ptrs是一个含有10个整形指针的数组
int(*parray)[10]=&arr;//parray指向一个含有10个整数的数组。*parray意味着parray是个指针,指向大小为10的数组,数组中的元素时int。
int *(&arry)[10]=ptrs;//arry是数组的应用,该数组含有10个指针。 由内向外,首先arry是个引用,然后引用对象是个大小为10的数组,然后数组的元素类型是指向int的指针。
3、使用数组类型的对象其实就是使用一个指向该数组首元素的指针。
4、c标准库的string函数:(传入以下函数的指针必须指向以空字符为结束的数组:‘\0’)
strlen(p):返回p的长度,空字符不算在内
strcmp(p1,p2):比较p1p2的相等性,如果p1==p2返回0,p1>p2返回正值,p1<p2返回负值。
strcat(p1,p2):将p2附加到p1后面,返回p1
strcpy(p1,p2):将p1拷贝给p2,返回p1
1 int main(){ 2 char ca[]={'c','+','+','\0'}; 3 char da[]={'c','-','-','\0'}; 4 cout<<strlen(ca)<<endl; //3 5 cout<<strcmp(ca,da)<<endl; //-1 6 cout<<strcat(ca,da)<<endl; //c++c-- 7 cout<<strcpy(ca,da)<<endl; //c++ 8 return 0; 9 }
六、多维数组
1、多维数组其实是数组的数组,多维数组名转换得来的指针其实是指向第一个内层数组的指针。
2、使用类型别名简化多维数组的指针://将类型“四个整数组成的数组”命名为int_array
using int_array = int[4]; //新标准下类型别名的声明
typedef int int_array[4]; //等价的typedef声明
第三章结束。进度不是很快,上手能力并没有太大的提升,得加入编程训练了。且随疾风前行。