《C++primer》读书笔记---第三章:字符串、向量和数组

3.1命名空间的using声明

  在前几章的内容中,几乎在使用所有的标准库函数时,都i要在前面加上std::,这种方法较为繁琐,在本节中介绍了一种新的方法:使用using声明,其具体使用方法是:

//using namespace ::name;
//例如:
using std::cin;

  在代码的开头进行上述声明,在接下来使用标准输入函数cin时,不需要在前面加上std::。需要注意的一点是,每个名字都需要独立的using声明。

3.2标准库类型string

  string属于标准库,在使用时应包含头文件string,且加上std::

#include <string>
using std::string;

下面是初始化string对象最常用的一些方式:

string s1;//默认初始化,S1是一个空字符串
string s2 = s1;//s2是s1的副本
string s3 = "hiya";//s3是该字符串字面值的副本
string s4(10,'c');//s4的内容是cccccccccc

下表列出了string的大多数操作,读者可以稍微阅读:
在这里插入图片描述
  第一章中使用iostream来读写int、double等内置类型,同样string也可以用io操作符进行读写

string s;
cin >> s;
cout << s <<endl;

这段程序定义了一个名为s 的空字符串,然后将标准输入的内容读取到s中,在读取时,string对象会自动忽略开头的空白(空格符、换行符、制表符等)并从第一个真正的字符读取,直到遇见第一个空白为止。所以,如果上述程序输入的是“ hello world ”,则输出将是“hello”,输出结果中没有任何空格。
  有时,我们需要读取输入的整句英文,而不是一个单独的单词,显然cin无法实现我们的要求,这是需要一个新的函数getline,它的用法如下:

string line;
getline(cin,line);

getline函数的参数是一个输入流和一个string对象,函数从给定的输入流读入内容,直到遇到换行符(注意换行符也被读进来了),然后把所读的内容存到string对象中(注意不存换行符),如果输入的一开始就是换行符,那么所得的结果就是个空string。

string的empty和size操作

  empty函数根据string对象是否为空返回一个对应的布尔值,size函数返回string对象的长度,这两个函数的用法如下:

string s;
if(!s.empty())
	cout<<s<<endl;//输出非空的行
if(s.size()>80)
	cout<<s<<endl;//输出长度大于80个字符的行

对于size函数来说,其返回值是一个string::size_type类型的值,过去,string::size_type类型有些神秘,但在C++11新标准中,允许使用auto或者decltype来推断类型:

string s;
auto len = s.size();

比较string对象

  使用==或者!=分别检验两个string对象相等或不相等,如果两个 string 对象的长度不同,而且较短string 对象的每个字符都与较长string 对象对应位置上的字符相同,就说较短string对象小于较长string对象。如果两个 string 对象在某些对应的位置上不一致,则string 对象比较的结果其实是string 对象中第一对相异字符比较的结果。
下面是string对象比较的一个示例:

string str="Hello";
string phrase ="Hello World";
string slang ="Hiya";

根据规则1可判断,对象str小于对象phrase;根据规则2可判断,对象slang 既大于str也大于 phrase。

两个string对象相加

使用+可以将两个string对象相加,例如:

string sl="hello,",s2="world\n";
string s3=sl+s2;//s3的内容是hello,world\n
s1 += s2;//等价于s1=s1+s2

string对象和字面值相加

当string对象和字面值相加时,必须保证有一方为string对象:

string s4=sl+" ";//正确:把一个string对象和一个字面值相加
string s5="hello"+",";//错误:两个运算对象都不是string

string s6=s1+""+"world"//正确:每个加法运算符都有一个运算对象是string
string s7="hello”+ ","+s2;//错误:不能把字面值直接相加

其中s6s7需要做下解释:
s6可以写为(s1+“ ”)+“world”,其中,左侧为string对象,右侧为字面值,符合相加规则;
s7可以写为(“hello”+“,”)+s2,其中,左侧右侧都为字面值,不符合相加规则;

处理string对象的字符

想要处理string对象中的每一个字符,可以使用C++11的新标准:范围for语句,使用方法是:

string str("some string");
for(auto c: str)//对于str中的每个字符
	cout << c << endl;

for循环将变量c和str联系起来,其中,每次迭代,str的下一个字符被拷贝给c,因此该循环可以被读为“对于str中的每个字符”
  可以使用for语句改变字符中的元素,此时要将左边的变量定义为引用的形式。
  可以像处理数组的方式来处理string对象,下标的值称为下标或者索引,例如:s[0]代表string对象的第一个元素。

标准库类型vector

  标准库类型vector表示对象的集合,它通常被成为容器,vector属于标准库,所以在使用时需要在前面添加std::,并且在代码的开头包含vector头文件,下面是vector的用法示例:

#include <vector>
using std::vector;
int main()
{
	vector<int> ivec;//ivec保存int类型的对象
	return 0;
}

初始化vector对象的方法与前面章节所介绍的类似,下表列出了常用的初始化方法:
在这里插入图片描述
注意,当参数只有一个整数时,要区分整数的含义是对象的容量还是元素的值,主要依据是传递初始值时使用的时圆括号还是尖括号,下面的例子可以帮助读者理解:

vector<int> v1(10);//v1有十个元素,每个元素都是0
vector<int> v2{10};//v2有一个元素,其值为10

向vector对象中添加元素

  对vector对象来说,直接初始化的方式适用于三种情况:初始值已知且数量较少初始值是另一个 vector对象的副本、所有元素的初始值都一样。更常见 的用法是创建一个空的vector对象,在运行时利用vector的成员函数push_back向其中添加元素。

vector<int> v2;//创建一个空的vector对象
for(itn i = 0; i ! = 100;++i)
	v2.push_back(i);//依次把整数放到v2的尾端

在这个程序中,我们没有在创建vector对象时指定大小,这是因为在运行时,vector可以快速高效的添加元素,所以在定义时就没有必要指明他的大小。
除了push_back外,vector的大部分操作都与string类似,下表列出了vector常用的操作:
在这里插入图片描述

计算vector内的对象索引

  和string类似,使用下标可以精确访问到vector对象内的元素,但是有一点要注意的是,不能使用下标向vector内添加元素:

vector<int> ivec;
for(decltype(ivec.size()) ix = 0 ;ix ! = 10;++ix))
	ivec[ix] = ix;//严重错误,ivec中不包含任何元素

所以,只有明确存在的元素才能使用下标进行操作。

3.4迭代器介绍

  在前面介绍过使用下标来访问容器中的元素,本节中将会介绍另外一种访问容器元素的方式,它被称为迭代器,除了vector容器外,标准库中还定义了许多其他的容器,并不是所有的容器都可以使用下标访问元素,但是所有的容器都可以使用迭代器来访问,需要注意的是,虽然string对象也可以使用迭代器,但严格来讲,string并不属于容器。

迭代器的使用

  有迭代器的类型通常有返回迭代器的成员,比如这些类型都拥有名为begin和end的成员,其中begin成员负责返回指向第一个元素的迭代器,end负责返回指向容器尾元素下一位置的迭代器,也就是说,该迭代器指示的是容器本不存在的“尾后”元素。特殊情况下,如果容器为空,则begin和end返回的是同一个迭代器。

auto b = v.begin();
auto e = v.end();

迭代器运算符

在这里插入图片描述
与指针类似,迭代器可以通过解引用的操作来获取它所指示的元素,并且试图解引用一个非法的迭代器或者尾后迭代器都是未定义的行为。
迭代器也可以使用递增运算符来从一个元素移动到下一个元素。

3.5数组

  与vector容器类似,数组也是存放某种类型对象的元素,但是数组和vector容器之间还是有较大的差别,其中一条便是,在创建数组时,必须显示的声明数组的大小,且这个大小在之后也无法改变(后面使用new操作符,可以在创建数组是使用变量,即在程序运行时才确定数组的大小,本章不做具体讨论),数组的创建方法如下:

int arr[10];//含有十个整数的数组
int *arr2[10];//含有十个整形指针的数组
int arr3[] = {0,1,2};//大小为三的数组

并且在默认情况下,数组的元素会被默认初始化。在定义数组时必须明确指出数组的类型,不能使用auto关键字.
另一个与vector不同的是,数组不允许拷贝初始化:

int a[] = {0,1,2};//含有三个元素的数组
int a2[] = a;//错误,不允许使用一个数组来初始化另一个数组
a2 = a;//错误,不能将一个数组给另一个数组赋值

理解数组的复杂声明

下面是一些较为复杂的数组说明

int *ptrs[10];//含有十个整形指针的数组
int &refs[10] = /*?*/;//错误:不存在引用的数组
int (*Parry)[10] = &arr;//指向一个含有十个整数的数组
int (&arrRef)[10] = arr;//引用一个含有十个整数的数组

由内向外的顺序可帮助我们更好地理解Parray的含义:首先是圆括号括起来的部分,*Parray意味着Parray是个指针,接下来观察右边,可知道Parray是个指向大小为10的数组的指针,最后观察左边,知道数组中的元素是int。这样最终的含义就明白无误了,Parray是个指针,它指向一个 int 数组,数组中包含 10个元素。同理,(&arrRef)表示 arrRef是一个引用,它引用的对象是一个大小为10的数组,数组中元素的类型是int。

指针与数组

  在c++中指针和数组有密切的联系,在使用数组的时候。编译器通常会把他转换为指针。尽管能计算得到尾后指针,但这种方法容易出错,C++11新标准引入了两个名为begin和end的函数,这两个函数与容器中的同名成员函数类似,但数组不是类类型,因此两个函数都不是成员函数。

int i[] = {0,1,2,3,4};
int *beg = begin(ia);//指向ia的首元素
int *last = end(ia);//指向ia的尾元素的下一位置指针

3.6多维数组

  严格来说,C++没有多维数组,通常所说的多维数组是指数组的数组。当一个数组的元素仍为数组时,通常使用两个维度来定义它:一个维度表示数组本身大小,另一个维度表示其元素(也是数组)大小:

int ia[3][4];//大小是三的数组,每个元素是含有四个元素的数组

多维数组的初始化

对于二维数组来说,我们通常把第一个维度称为行,第二个维度称为列,它的初始化方式为:

int ia[3][4] = {
	{0,1,2,3},
	{4,5,6,7},
	{8,9,10,11}
};//其中内层嵌套的花括号不是必须的,也可以使用下面的方法进行初始化
int ia2[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
//如果想仅仅初始化每行的首元素:
int ia3[3][4] = {{0},{4},{8}};//其他未列出的元素执行默认初始化

指针和多维数组

  与一维数组类似,但有一点需要注意的地方:定义指向多维数组的指针时,千万别忘了这个多维数组实际上是数组的数组,所以由多维数组名转换来的指针实际上是指向第一个内层数组的指针。

小结

本章内容较多,尤其关于多维数组的内容较难理解,读者还需阅读原书才能更好的掌握本章的知识、(由于篇幅的缘故,本章的随堂练习将放在下一篇博客中)

  • 26
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值