C++ Primer学习笔记

第一章 开始

  1. return,它结束函数的执行。(P2)

  2. 一个流就是一个字符序列,术语“流”想表达的是,随着时间的推移,字符是顺序生成或消耗的。(P5)

  3. 写入endl的效果是结束当前行,并将与设备关联的缓冲区中的内容刷到设备中,在调试时添加打印语句,应该保证“一直”刷新流。(P6)

  4. 注释界定符中,注释内的每行都以一个星号开头。(P8)

  5. 如果注释界定符成对出现,成对的界定符优先。(P9中的练习题)

  6. while(std::cin>>value)中,循环条件实际上检测的时std::cin,当使用一个istream对象作为条件时,其效果是检测流的状态,如果流是有效的,未遇到错误,那么检测成功,当遇到文件结束符,或无效输入的时候,istream对象的状态无效,此时条件为假。(P13)

  7. 标准库头文件通常不带后缀。(P17)

  8. 对于不属于标准库的头文件,用双引号包围,标准库头文件用<>包围。(P19)

  9. C++是一种静态类型语言,它的类型检查发生在编译时。(P28)

第二章 变量和基本类型

  1. 一个char的空间应确保可以存放基本字符集中任意字符对应的数字值,也就是说一个char的大小和一个机器字节一样。(P30)

  2. 可寻址的最小内存块称为“字节”,存储的基本单元成为“字”。(P31)

  3. 一般来说,类型float和double分别有7和16个有效位。(P31)

  4. 类型unsigned int 可以缩写为unsigned。(P31)

  5. 带符号数和无符号数一起运算时,带符号数会自动转化为无符号数。(P35)

  6. 默认情况下,十进制字面值是带符号数,八进制和十六进制字面值可能是带符号的也可能是无符号的,十进制字面值的类型是int、long、long long中尺寸最小的那个(前提是这种类型要能容纳下当前的值),short没有对应的字面值,严格来说,十进制字面值不会是负数,对一个形如-42的值来说,那个负号并不在字面值内,它的作用仅是对字面值取负值而已。默认的,浮点型字面值是一个double。(P35)

  7. 字符串字面值的类型实际上是由常量字符构成的数组,编译器在每个字符串的结尾处添加一个空字符(’\0’),如果两个字符串字面值位置紧邻且仅由空格、缩进和换行符分隔,则它们实际上是一个整体。(P36)

  8. \x后紧跟1个或多个十六进制数字,或者\后紧跟1个、2个或3个八进制数字,如果反斜线\后面跟着的八进制数字超过3个,只有前3个数字与\构成转义序列,而\x要用到后面跟着的所有数字。(P37)

  9. 初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来替代。(P39)

  10. 如果使用列表初始化,但初始值存在丢失信息的风险,编译器将报错。(P39)

  11. 函数体之外的变量默认初始化为0,函数体内的内置类型变量将不被初始化。类的对象如果没有显式地初始化,则其值由类确定。(P40)

  12. 如果想声明一个变量而非定义它,就在变量名前添加extern,而且不要显式地初始化变量。extern语句如果包含初始值就不再是声明,而变成定义了。在函数体内部,如果试图初始化一个由extern关键字标记的变量,将引发错误。(P41)

  13. 标识符长度没有限制,对大小写字母敏感,用户自定义的标识符中不能连续出现两个下划线,也不能以下划线紧连大写字母开头,定义在函数体外的标识符不能以下划线开头。(P42)

  14. 建议:当你第一次使用变量时再定义它。(P44)

  15. ::reused,显式地访问全局变量。(P44)

  16. 引用必须被初始化,一旦初始化完成,将和它的初始值对象一直绑定在一起。为引用赋值,实际上是把值赋给了与引用绑定的对象,获取 引用的值,实际上是获取了与引用绑定的对象的值。(P46)

  17. 引用本身不是对象,所以不能定义引用的引用。(P46)

  18. 引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起。(P46)

  19. 指针本身就是一个对象,因为引用不是一个对象,没有实际地址,所以不能定义指向引用的指针。(P47)

  20. NULL是一个预处理变量,这个变量在头文件cstdlib中定义,它的值就是0。(P49)

  21. 如果指针的 值是0,条件取false,任何非0指针对应的条件值都是true,如果两个指针存放的地址值相同 ,则它们相等。两个指针相等 ,有三种情况:它们都为空、都指向同一个对象,或者都指向了同一个对象的下一个地址,注意的是,一个指针指向某对象,同时另一个指针指向对象的下一地址,也有可能出现指针相等的情况。(P50)

  22. void*存放任意对象的地址,这种指针能做的事有限:和别的指针比较、作为函数的输入或输出、赋给另外一个这种类型的指针,这种指针所指的对象不能直接操作,因为我们不知道这个对象到底是什么类型,也无法确定能在这个对象上做哪些操作。(P50)

  23. 存在对指针的引用,面对一条比较复杂的指针或者引用时,从右向左读。(P53)

  24. const对象必须初始化,默认情况下,const对象被设定为仅在文件内有效,如果确实需要在文件内共享,不管是声明还是定义都添加extern关键字。(P54)

  25. 常量对象只能由常量引用指向,但允许一个常量引用绑定非常量的对象、字面值甚至是一个一般表达式。(P55)

  26. 存放常量对象的地址,只能使用指向常量的指针。但允许一个指向常量的指针指向一个非常量对象。(P56)

  27. 顶层const表示指针本身是个常量,底层const表示指针指向的对象是一个常量。(P57)

  28. 一般来说,如果认定变量是一个常量表达式,那就把它声明成constexpr类型。(P59)

  29. 一个constexpr指针的初始值必须是nullptr或者0,或者是存储与某个固定地址中的对象,函数体内定义的变量并非存放在固定地址中,例外是允许函数定义一类有效范围超出本身的变量,这类变量和定义在函数体外的变量一样有固定地址。(P59)

  30. 限定符constexpr仅对指针有效,与指针所指的对象无关,是因为constexpr把它所定义的对象置为了顶层const。(P60)

  31. 如果某个类型别名指代的是复合类型和常量,当用const修饰的时候,const是对给定类型的修饰。(P61)

  32. auto定义的变量必须有初始值,,auto在一条语句中声明多个变量时,该语句中所有变量的初始基本数据类型必须一样。(P61)

  33. auto一般会忽略掉顶层const,同时保留底层const,如果希望推断出的auto类型是一个顶层const,需要加const明确指出,设置一个类型为auto的引用时,初始值中的顶层常量属性仍然保留。(P62)

  34. 如果decltype使用的表达式是一个变量,则decltype返回该变量的类型包括顶层const和引用在内。(P63)

  35. decltype中如果表达式内容是一个解引用操作,则decltype将得到一个引用类型。(P63)

  36. decltype的表达式如果是加上了括号的变量,结果将是引用。(P63)

  37. 头文件一旦改变,相关的源文件必须重新编译以获取更新过的声明。(P68)

  38. 头文件保护符。(P68)

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

  1. string定义在命名空间std中。(P75)

  2. 使用字面值初始化一个string时,除了最后那个空字符外其他所有字符都被拷贝到新创建的string对象中去。(P76)

  3. 对于用多个值进行初始化string时,如果非要使用拷贝初始化,必须显式地创建一个(临时)对象用于拷贝。(P76)

  4. string对象的相等性判断对大小写敏感。(P77)

  5. 使用cin直接进行操作时,string对象会自动忽略开头的空白(空格符、换行符、制表符等)并从第一个真正的字符开始读起,直至遇见下一处空白为止。(P77)

  6. 使用getline()操作时,返回 一整行,直至遇到换行符为止,换行符虽然也被读进来了,但是不存换行符,直接丢弃换行符,它的作用仅是触发getline函数返回。(P78)

  7. size函数返回的是一个string::size_type类型的值,它是一个无符号类型的值,如果表达式中有size函数就不要再使用int,这样可以避免混用int和unsigned可能带来的问题。(P79)

  8. 使用加法运算符(+)的两侧的运算对象至少有一个是string。C++语言中的字符串字面值并不是标准库类型string的对象,它们是不同的类型。(P81)

  9. 总是设下标的类型为size_type,因为此类型是无符号数,可以确保下标不会小于0,只需要保证下标小于size()的值就可以了。(P85)

  10. 在初始化vector时,如果确认无法执行列表初始化,编译器会尝试用默认值初始化vector对象。(P89)

  11. 范围for语句体内不应改变其所遍历序列的大小。(P91)

  12. vector对象以及string对象的下标运算符可用于访问已存在的元素,而不能用于添加元素,确保下标合法的一种手段就是尽可能使用范围for语句。(P94)

  13. begin返回的是第一个元素的迭代器,end返回的是最后一个元素的下一个位置,称为尾后迭代器,如果容器为空,则begin和end返回的是同一个迭代器,都是尾后迭代器。(P95)

  14. iter->mem,解引用iter并获取该元素的名为mem的成员,等价于(*iter).mem,养成使用迭代器和!=的习惯。(P97)

  15. const_iterator能读取但不能修改它所指的元素值,iterator的对象可读可写,如果vector或string对象是一个常量,只能使用const_iterator,如果不是常量,那iterator和const_iterator都可以。(P97)

  16. 使用cbegin和cend,不论vector对象本身是否是常量,返回值都是const_iterator。(P98)

  17. 但凡是使用了迭代器的循环体,都不要向迭代器所属的容器添加元素。两个迭代器相减的结果是它们之间的距离,这个距离可正可负,类型是difference_type的带符号整型数。(P99)

  18. 使用迭代器进行二分搜索。(P100)

  19. 数组的大小确定不变,运行时性能较好 ,但损失了一些灵活性。(P101)

  20. 定义数组的类型时,不允许用auto关键字。(P102)

  21. 用字符串字面值初始化一个字符数组时,最后的\0字符也会被拷贝到字符数组中去。(P102)

  22. 理解数组声明的含义,从数组的名字开始按照由内向外的顺序阅读。(P103)

  23. 数组下标的类型通常定义为size_t类型,它是一个机器相关的无符号类型。(P103)

  24. 直接使用数组名其实是一个指向该数组首元素的指针,当它作为auto变量的初始值时,推断得到的类型是指针而非数组,但是使用decltype关键字时上述转换不会发生,得到的类型将是一个数组。(P105)

  25. 标准库中的begin和end函数与容器中的两个同名函数功能类型,不过数组毕竟不是类类型,因此这两个函数不是成员函数,正确的使用形式是将数组作为它们的参数,这两个函数定义在iterator头文件中。(P106)

  26. 两个指针相减的结果的类型是一种名为ptrdiff_t的标准库类型,和size_t一样,ptrdiff_t也是一种定义在cstddef头文件中的机器相关的类型,它是一种带符号类型。(P107)

  27. 标准库类型限定使用的下标必须是无符号类型,而内置的下标运算无此要求。(P108)

  28. C标准库String函数中,例如strlen(),传入此类函数的指针必须指向以空字符作为结束的数组。(P109)

  29. string专门提供了一个名为c_str的成员函数,它的返回值是一个C风格的字符串,也就是一个指针,该指针指向一个以空字符结束的字符数组,指针类型是const char*。如果后续操作改变了s的值就可能让之前返回的数组失去效用,最好将该数组重新拷贝一份。(P111)

  30. 尽量使用vector和迭代器,避免使用内置数组和指针,应该尽量使用string,避免使用C风格的基于数组的字符串。(P112)

  31. 多维数组就是数组的数组,对与二维数组来说,常把第一个维度称作行,第二个维度称作列。(P112)

  32. 使用范围for语句处理多维数组时,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型。(P114)

第四章 表达式

  1. 小整数类型(bool、char、short等)通常会被提升成较大的整数类型,主要是int。(P120)
  2. 当一个对象被用作右值的时候,用的是对象的值(内容),当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。(P121)
  3. <<运算符没有明确规定何时以及如何对运算对象求值。(P123)
  4. 拿不准的时候最好用括号来强制让表达式的组合关系符合程序逻辑的要求。如果改变了某个运算对象的值,在表达式的其他地方不要再使用这个运算对象,重要例外是当改变运算对象的子表达式本身就是另一个子表达式的运算对象时该规则无效。(P124)
  5. 整数相除结果是整数,取余运算的运算对象必须是整数类型,m%n的符号和m相同。(P125)
  6. 使用复合运算符只求值一次,使用普通的运算符则求值两次。(P131)
  7. 除非必须,否则不用递增递减运算符的后置版本。因为后置版本需要将原始值存储下来,对于复杂的迭代器类型,这种额外开销很大。(P132)
  8. 条件运算符(?:)的优先级非常低,因此当一条长表达式中嵌套了条件运算表达式时,通常需要在它两端加上括号,比如输出语句中。(P135)
  9. 关于符号位如何处理没有明确规定,所以强烈建议仅将位运算符用于处理无符号类型。(P136)
  10. sizeof运算符返回一条表达式或一个类型名字所占的字节数,满足右结合律,所得值是一个size_t类型的常量表达式,sizeof并不实际计算其运算对象的值,在sizeof的运算对象中解引用一个无效指针仍然是一种安全行为,还可以使用作用域运算符来获取类成员的大小。sizeof不会把数组转换成指针来处理,它会得到数组所占空间的大小。(P139)
  11. 逗号运算符首先对左侧表达式求值,然后将求值结果丢弃掉,真正的结果是右侧表达式的值。(P140)