类型长度,但是却没有计算表达式 expr 的值!
(特别是在 sizeof *p 中,指针 p 可以持有一个无效地址,因为不需要对 p 做解引用操作。)
9.逗号操作符:结果是其最右边表达式的值;常用于for循环。
10.类型转换:隐式类型转换(implicit type conversion)、算术转换(arithmetic conversion )、显式转换(强制类型转换cast)
1)何时发生隐式类型转换
混合类型的表达式、条件表达式被转换为bool类型、用表达式初始化(或赋值)变量时、函数调用。
2)强制类型转换(static_cast、dynamic_cast、const_cast、reinterpret_cast)(尽量避免使用)
旧式强制类型转换
type (expr);//Function-style cast notation
(type) expr;//C-language-style cast notation
语句
1.使用空语句时应该加上注释,以便任何读这段代码的人都知道该语句是有意省略的。
2.复合语句(compound statement),通常被称为块(block),是用一对花括号括起来的语句序列。
复合语句用在语法规则要求使用单个语句但程序逻辑却需要不止一个语句的地方。(例:循环语句的循环体)->复合语句在语法上是单个语句
3.一个类类型能否用在条件表达式中取决于类本身。(IO类型可以)
4.switch语句提供了一种更方便的方法来实现深层嵌套的if/else逻辑。
case label的执行流:从该点开始执行,并跨越case边界继续执行其他语句,直到switch结束或遇到break语句为止。(故意省略case后面的break语句时,应提供一些注释说明)
default label提供了相当于else子句的功能。(定义default标号是为了告诉它的读者,表面这种情况已经考虑到了)
为了避免出现代码跳过变量的定义和初始化的情况,对于switch结构,只能在它的最后一个case标号或default标号后面定义(作用域为整个switch的)变量。块语句例外。
5.do while语句总是以分号结束。
6.break语句用于结束最近的while、do while、for或switch语句,并将程序的执行权传递给紧接在被终止语句之后的语句。
7.continue语句导致最近的循环语句的当次迭代提前结束。只能出现在for、while或do while循环中。
8.throw表达式、try块(try block)、catch子句(catch clause)/处理代码(handler)、异常类(exception class)
寻找处理代码的过程与函数调用链刚好相反。(balabala)
9.使用预处理器进行调试
思想:程序所包含的调试代码仅在开发过程中执行。当应用程序已经完成,并且准备提交时,就会将调试代码关闭。
int main(){
#ifndef NDEBUG
cerr<< "starting main"<
使用NDEBUG预处理变量以及assert预处理宏进行调试。
与异常(异常用于处理程序执行时预期要发生的错误)不同,程序员使用assert来测试“不可能发生”的条件。
函数
形参(parameter)、调用操作符(call operator即一对圆括号)、实参(argument)
1.函数调用(做了两件事情):用对应的实参初始化函数的形参;并将控制权转移给被调用函数。主调函数(calling function)的执行被挂起,被调函数(called function)开始执行。
2.在C语言中,具有const形参或非const形参的函数并无区别。C++为了兼容C,所以、、、
3.复制实参的局限性。解决办法:将形参定义为引用或指针类型。(从C语言背景转到C++的程序员习惯通过传递指针来实现对实参的访问。在C++中,使用引用形参则更安全和更自然)
4.非const形参:避免复制实参;且使用引用形参返回额外的信息(也可通过额外的引用参数返回)。
const形参:避免复制实参,且防止修改相应实参。
应该将不需要修改的引用形参定义为const引用。普通的非const引用形参在使用时不太灵活:既不能用const对象初始化,也不能用字面值或产生右值的表达式实参初始化。
5.传递指向指针的引用
void ptrswap(int *&v1, int *&v2){ //int *&v1的定义应从右至左理解:v1是一个引用,与指向int型对象的指针相关联。
int *tmp = v2;
v2 = v1;
vi = tmp;
}交换指向对象的指针,来代替,交换指针指向的对象~(提高性能?只是某些时候吧?)
6.C++更倾向于通过传递指向容器中需要处理的元素的迭代器来传递容器。
7.数组形参,编译器忽略任何数组形参指定的长度。
通过引用传递数组,数组大小成为形参和实参类型的一部分,编译器检查数组实参的大小与形参的大小是否匹配。
f(int (&arr)[10]) //arr is a reference to an array of 10 ints
f(int &arr[10]) //arr is an array of references
8.多维数组的传递:编译器忽略第一维的长度。
void printValues(int matrix[][10], int rowSize)
9.任何处理数组的程序都要确保程序停留在数组的边界内。有三种常见的编程技巧:
1)在数组本身放置一个标记来检测数组的结束。(例如,C风格字符串)
2)传递指向数组第一个和最后一个元素的下一个位置的指针。(标准库中的技术)
3)将第二个形参定义为表示数组的大小。这种用法在C程序和标准化之前的C++程序中十分普遍。
10.省略符形参:暂停了类型检查机制。
11.return语句
没有返回值的函数:return;(或者隐式的)
具有返回值的函数:return expression;
在含有return语句的循环后没有提供return语句是很危险的,因为大部分的编译器不能检测出这个漏洞。
千万不要返回局部对象的引用或指针!
12.函数原型(function prototype)=函数返回值+函数名+形参列表
13.默认实参:既可以在函数声明也可以在函数定义中指定默认实参。但是在一个文件中,只能指定一次默认实参。
通常,应在函数声明中指定默认实参,并将该声明放在合适的头文件中。(另:只有文件中包含默认实参时,默认实参才是有效的)
14.自动对象(automatic object)、static局部对象(static local object)
size_t count_calls(){
static size_t ctr = 0;
return ++ctr;
}15.内联函数避免函数调用的开销(调用函数要比求解等价表达式要慢得多)。
将函数指定为内联函数,就是讲它在程序中每个调用点上“内联地”展开。
内联机制适用于优化小的、只有几行的而且经常被调用的函数。
内联函数应该在头文件中定义!
16.类的成员函数:this指针、常量成员函数(con