《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函数:(传入以下函数的指针必须指向以空字符为结束的数组:‘’)

  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','+','+',''};
 3     char da[]={'c','-','-',''};
 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声明

 

第三章结束。进度不是很快,上手能力并没有太大的提升,得加入编程训练了。且随疾风前行。

原文地址:https://www.cnblogs.com/zlz099/p/6437755.html