天天看点

《C++Primer》读书笔记——第3章 字符串、向量和数组

  1. using声明语法:using namespace::name;如,using std:cin;
  2. 头文件不应该包括using声明
  3. 初始化string对象的方式:
    1. string s1;//默认初始化,s1是个空串
    2. string s2(s1);//s2是s1的副本
    3. string s2 = s1;//等价于s2(s1),s2是s1的副本
    4. string s4(n,’c’)//把s4初始化为由连续n个字符c组成的串

      ps:2、4为直接初始化(没用=),3为拷贝初始化(用了=),4可转换为拷贝初始化:string s4 = string(n,’c’);

  4. string的基本操作
    1. os << s;
    2. is >> s;
    3. getline(is, s);//从is中读一行赋给s,返回is
    4. s.empty();s为空,返回true
    5. s.size();返回s中字符的个数
    6. s1+s2;返回s1 s2的连接
    7. s1==s2;
    8. s1!=s2;
    9. s1>=s2;(> <= <)//字典序比较
  5. size()函数返回值类型为string::size_type类型,size_type是无符号的,Tips:如果一条表达式中已经有size()函数了,就不要再用int了,这样可以避免混用int和unsigned可能带来的问题
  6. 字符串+操作:不能将字面值与字面值直接相加

    tips:C++语言中的字符串字面值并不是标准库类型string的对象。切记:字符串字面值与string是不同的类型

  7. cctype头文件中的函数
    1. isalnum(c);当c是字母或数字时为真
    2. isdight(c);当c是数字时为真
    3. isxdight(c);当c是16进制数字时为真
    4. isalpha(c);当c是字母时为真
    5. islower(c);当c是小写字母时为真
    6. isupper(c);当c是大写字母时为真
    7. iscntrl(c);当c是控制字符时为真
    8. isgraph(c);当c 可打印但不是空格时为真
    9. isprint(c);当c是可打印字符时为真(c具有可视形式或c是空格)
    10. isspace(c);当c是空白时为真(即c是空格、横向制表符、数字、字母、可打印空白中的一种)
    11. ispunct(c);当c是标点符号时为真(即c不是控制字符、数字、字母、可打印空白中的一种)
    12. tolower;转换为小写字母
    13. toupper;转换为大写字母
  8. Tips:建议使用C++版本的C标准库头文件。

    C++标准库中除了定义C++语言特有功能外,也兼容了C语言的标准库,只不过将名字由name.h转变为cname。一般使用cname形式的头文件

  9. string中单个字符类型为char
  10. 要想访问string对象中的单个字符有两种方式,一种是使用下标,一种是使用迭代器。

    下标运算符[],下标的值成为下标或索引

  11. C++语言既有类模板,又有函数模板,其中vector是一个类模板。模板本身不是类和函数。编译器根据模板创建类或函数的过程称为实例化。
  12. 对于类模板,我们提供一些额外信息来制定模板到底实例化乘什么样的类,需要提供哪些信息由模板决定。

    提供信息的方式总是这样:即在模板名字后面加一个尖括号,在括号内放上信息。

    以vector为例,提供的额外信息是vector内所存放对象的类型,如:vector< int> ivec;

  13. 初始化vector对象的方法
    1. vector< T> v1//v1是一个空vector,执行默认初始化
    2. vector< T> v2(v1)//v2中包含所以v1元素的副本
    3. vector< T> v2 = v1//等价于v2(v1)
    4. vector< T> v3(n, val)//v3包含了n个值val的元素
    5. vector< T> v4(n)//v4包含了n个默认初始化的元素
    6. vector< T> v5{a,b,c,d…}//v5包含的每个元素被赋予特定值。PS:一定注意是花括号!!!
    7. vector< T> v5 = {a,b,c,d…}//等价于v5{a,b,c,d…}
    8. 特例:vector< string> v7{10};vector< string> v7{10,”hi”}都是正确的
  14. vector支持的操作
    1. v.empty()如果v为空,返回true
    2. v.size返回v中元素的个数
    3. v.push_back(t)向v的尾端添加一个值为t的元素
    4. v[n]下标访问
    5. v1 == v2 v1 != v2
    6. < <= > >=
  15. 不能以下表的形式添加元素。只能对已存在的元素执行下表操作,试图用下标访问一个不存在的元素将引发错误,会导致错误,如buffer overflow(缓冲区溢出)
  16. 迭代器——访问string vector的另一种途径。

    标准库容器都支持迭代器,只有其中的几种支持下标访问。

    类似于指针,迭代器也实现了元素的间接访问

    严格来说,string类型不属于容器类型,但是string支持很多与容器类似的操作。

  17. v.begin() 返回指向第一个元素的迭代器

    v.end() 返回指向容器“尾元素的下一位置”的迭代器,被称作尾后迭代器,尾迭代器。没有实际含义,只作为一个标记

    如果容器为空,则begin() end()返回的是同一个迭代器,都是尾后迭代器

  18. 标准容器迭代器的运算符
    1. *iter 返回迭代器iter所指元素的引用
    2. iter->men 解引用iter并获取钙元素的名为men的成员,等价于(*iter).men
    3. ++iter 令iter指示容器中的下一个元素
    4. –iter 上一个元素
    5. iter1 == iter2(iter1 != iter2) 判断是否相等
  19. 概念:泛型编程

    所有标准库容器都定义了==和!=,但它们中的大多数都没有定义<运算符。养成用迭代器和!=的习惯,就不用太在意用的到底是哪种容器了。

  20. 迭代器类型:iterator和const_iterator(只读不能写)
  21. vector对象可以动态增长,但也带来了副作用。
    1. 不能在范围for循环中向vector对象添加元素。
    2. 任何一种可能改变vector对象容量的操作,比如push_back,都会使该对象的迭代器失效

      Tips:凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素。

  22. vector 和 string支持的迭代器运算
    1. iter+n(iter-n)
    2. iter1-iter2 返回它们之间的距离,类型为difference_type的带符号整形数
    3. > >= < <= 迭代器的关系运算器,若在前面则小于
  23. 数组。和vector相比,相同点:也是存放类型相同的对象的容器,这些对象本身没有名字,需要通过其所在位置访问。不同点:数组大小固定不变,不能随意向数组中增加元素。某些场合运行时效率较好,但失去了灵活性。
  24. 定义和初始化内置数组
    1. 定义:数组的维度必须是一个常量表达式。如下面是正确的:

      constexpr int sz = 42;

      string strs[sz];

    2. 显示初始化数组元素

      int a2[] = {0, 1, 2};//维度是3

      int a3[5] = {0, 1, 2};//初始化了前3个元素

      int a5[2] = {0, 1, 2};//错误!初始值错误

    3. 字符数组的特殊性

      字符数组有一种额外的初始化形式,即可以用字符串字面值对此类数组初始化。但注意!字符串字面值的结尾处还有一个空字符,这个空字符也会像其他字符一样,被拷贝到字符数组里。

      char a1[] = {‘C’, ‘+’, ‘+’};//无空字符,维度为3

      char a2[] = {‘C’, ‘+’, ‘+’, ‘\0’};//有空字符,维度为4

      char a3[] = “C++”;//自动添加空字符,等同于上一句

      char a4[6] = “Daniel”;//错误:没有空间可存放空字符

    4. 不允许拷贝和赋值:不允许用一个数组初始化另一个数组,不能把一个数组直接赋值给另一个数组
    5. 理解复杂的数组声明:

      int *ptrs[10];

      int &refs[10] = ;//错误,不存在引用的数组

      int (*Parray)[10] = &arr;//Parray指向一个含有10个整数的数组

      int (&arrRef)[10] = arr;//arrRef引用一个含有10个整数的数组

  25. 数组下标通常定义为size_t类型。它在cstddef头文件中定义
  26. 指针和数组
    1. 使用数组类型的对象其实是使用该数组首元素的指针,

      string nums[] = {“one”, “two”, “three”};

      string *p = &nums[0];//p指向nums的第一个元素

      string *p2 = nums;//等价于p2 = &nums[]0; 即 nums == &nums[0]

      auto nums2(nums);//nums2是一个指针,等同于p p2

    2. 指针的运算 p1-p2 p1==p2 (!= > >= < <=)
    3. 指针的下标运算

      int *p = &ia[2];

      int j = p[1];//p[1] == *(p+1)

      int k = p[-2];//p[-2] == *(p-2)

  27. C风格字符串:字符串字面值:最后一个字符后面跟着一个空字符(’\0’)

    C标准库String函数(定义在cstring头文件中,注意区别于string头文件)

    1. strlen(p) 返回p的长度
    2. strcmp(p1, p2) p1==p2返回0 p1>p2返回正值 p1< p2返回负值
    3. strcat(p1, p2) 将p2附加到p1之后,返回p1
    4. strcpy(p1, p2) 将p2拷贝给p1,返回p1

      注意:传入此类函数的指针必须指向以空字符作为结束符的数组:如:

      char ca[] = {“C”, “+”, “+”};

      cout << strlen(ca) << endl;//严重错误:ca没有以’\0’结束

  28. 多维数组:严格来说,C++没有多维数组,通常多维数组其实是数组的数组。谨记!!
  29. 多维数组的初始化

    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}, {4}, {8} };//初始化首列,其余元素执行默认值初始化

    int ia[3][4] = {0,3,6,9};//初始化首行,其余元素执行默认值初始化