第3章 字符串、向量和数组

3.1 命名空间的using声明

每个名字都需要独立的using声明

头文件中不应该包含using声明

因为头文件的内容会拷贝到所有引用它的文件夹中去,如果头文件中有using声明,可能会产生始料未及的名字冲突。

3.2 标准库类型string

3.2.1 定义和初始化string对象

1
2
3
4
5
6
string s1;   //默认初始化
string s2=s1; //s2是s1的副本
string s2(s1); //等价于string s2=s1,s2是s1的副本
string s3="hiya"; //s3是字面值的副本,但是不包含字面值最后的那个空字符
string s3("hiya"); //等价于string s3="hiya"
string s4(n,'c'); //把s4初始化为连续n个字符c组成的字符串

3.2.2 string对象上的操作

  • 读写string对象
  • 读取未知数量的string对象
  • 使用getline读取一整行
  • string的empty和size操作

    string:size_type类型

    size_type是一种无符号整形数,如果在表达式中混用了带符号数和无符号数会产生意想不到的后果。

    比较string对象

    按字典顺序

    字面值和string类型相加

    1
    2
    3
    //错误的方式
    string s="hello"+"," //错误,因为两个运算对象都不是string,不能把两个字面值直接相加
    string s1="hello"+s1+"," //正确

字符串字面值与string是不同的类型

ex3.3 string类的输入运算和getline函数分别如何处理字符串

string的标准输入:自动忽略字符串开头的空白,从第一个真正的字符开始读取,直到下一个空白为止
getline函数:从给定的输入流中读取,直到遇到换行符为止。

3.3 标准库类型vector

vector是一种类模板,需要后加一堆尖括号,在括号内放上信息。

3.3.1 定义和初始化vector对象

  • 1.使用拷贝初始化
  • 2.如果提供一个类内的初始值,只能使用拷贝初始化或者花括号形式初始化
  • 3.如果提供的是初始值元素值的列表,则只能使用花括号初始化,而不能使用圆括号
  • 4.创建指定数量的元素:采用圆括号

    3.3.2 像vector中添加元素

    push_back:像一个值添加到vector的尾部。(如果开始不知道有多少元素,c++中,一般先创建一个空的vector然后像其中添加元素最好)
    不能使用下标形式添加元素,只能对确知已存在的元素执行下标操作。

3.4 迭代器介绍

迭代器这个名词可能有三种不同的含义:可能是迭代器概念本身,可能是容器定义的类型,还可能指某个迭代器对象。
某些对Vector对象的操作回事迭代器失效:一个是不能在范围for循环内向vector中添加元素,另一个是任何一种可能改变vector对象容量的操作,都有可能是vector对象的迭代器失效。

迭代器的算数运算

可以令迭代器和一个整数值相加(或相减),其返回值是向前(或向后)移动了若干个位置的迭代器。
迭代器之间的比较:参与比较的迭代器必须合法且指向同一个容器的元素(或者尾元素的下一个位置)

3.5 数组

数组与vector的区别:数组的大小确定不变,不能随意像数组中添加元素。性能很好,但是损失了灵活性。

3.5.1 定义和初始化数组

数组是一种复合类型,数组的维度必须是一个常量表达式。
定义数组的时候必须指定数组的类型。同时,数组的元素应该为对象,不存在引用的数组。

字符数组的特殊性

1
2
3
char a1[]={'C','+','+'};  //列表初始化,没有空字符
char a2[]={'C','+','+'}; //列表初始化,含有显式的空字符
char a3[]="C++"; //自动添加表示字符串结束的空字符

不允许拷贝和赋值

复杂的数组声明

要想理解数组的声明的含义,最好的办法是从数组的名字开始按照由内向外的顺序阅读

1
2
3
4
int &refs[10]=...  //  错误!不存在数组的引用
int (*Parray)[10]=&arr; //Parray指向一个含有10个整数的数组
int (&arrRef)[10]=arr //arrRef引用一个含有10个整数的数组
int *ptrs[10]; //ptrs是一个含有10个整型指针的数组

3.5.2 访问数组元素

  • 数组下标为 size_t类型 ,是一种机器相关的无符号类型。

    3.5.3 指针和数组

    使用数组的时候编译器一般会把它转化成指针

    指针也是迭代器

    允许使用递增运算符将指向数组元素的指针向前移动到下一个位置上

    标准库函数begin和end

    3.5.4 C风格字符串

    C风格字符串不是一种类型,而是为了表达和使用字符串而形成的一种约定俗成的写法。
    C风格字符串和字符数组的关系,尤其需要考虑串尾是否含有空字符。
    问题:为什么没有指针相加?
    指着也是一个对象,与指针有关的属性有三个,分别是指针的值(是一个内存地址值)、指针所指的对象、指针本身在内存中的存储位置。显然把两个地址加在一起是没有意义的。

    3.5.5 与旧代码的接口

    混用string对象和C风格字符串

  • 允许使用以空字符结束的字符数组来初始化string对象或为string对象赋值
  • 在string对象的加法运算中允许使用以空字符结束的字符数组作为其中一个运算对象(但不能两个都是);在string对象的赋值运算中允许以空字符串结束的字符数组作为右侧的运算对象。

    使用数组初始化vector对象

    允许使用数组初始化vector对象,只需要指明拷贝区域的首元素地址和尾后地址即可。但不能使用一个数组为另一个内置类型的数组赋初值,也不能使用vector对象初始化数组。

    3.6 多维数组

    严格来说,C++语言中没有多维数组,通常所说的多维数组其实是数组的数组。
    当一个数组的元素仍然是数组时,通常使用两个维度来定义它:一个维度表示数组本身大小,另一个维度表示其元素(也是数组)大小。
    1
    int ia[3][4] //大小为3的数组,每个元素是含有4个整数的数组