《C++ Primer》读书笔记(二)-变量和基本类型
- bool类型与其他类型转换时,0为false,1为true
- 浮点数赋值给整数的时候,进行近似处理,结果仅保留浮点数小数点之前的部分
- 整数赋值给浮点数的时候,小数部分记为0,如果该整数超过了浮点类型的容量,精度可能丢失
- 当我们赋给无符号类型一个超出它表示的范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。例如,8bit大小的unsigned char可以表示0至255区间内的值,如果我们赋了一个区间以外的值,则实际结果是该值对256取模后所得的余数。。因此把-1赋给unsigned char所得的结果是255.
- 当我们赋给符号类型一个超出它表示范围的值时,结果是未定义的,此时程序可能继续工作,可能崩溃,也可能生成垃圾数据。
使用无符号类型的表达式
//如果一个算术表达式中既有int类型,又有无符号数,int会转换为无符号数 unsigned u = 10; int i = -42; std::out<< i + i << std::endl; //输出-84 std::out<< u + i << std::endl; //把负数转换成无符号数,类似于直接给无符号数赋一个负值,结果等于这个负数加上无符号数的模。如果int占32位,输出4294967264 //当从一个无符号数中减去一个值时,不管这个值是不是无符号数,我们都必须确保结果不能是一个负数 unsigned u1 = 42, u2 = 10; std::out<< u1 - u2 <<std::endl; //正确:输出32 std::out<< u2 - u1 <<std::endl; //正确:不过结果是取模后的值 //无符号数在循环中的应用 //此处永远都不会输出0,u永远也不会小于0,此处会死循环 //每次当u=0,--u之后,-1被自动的转换成一个合法的无符号数 for(unsigned u = 10;u >= 0 ; --u) std::out<< u <<std::endl; //乘法运算同样存在上述现象 a = -1; b = 1; //如果a和b都是int类型,a*b 的结果肯定是 -1 //可是假如 b 是 unsigned,则结果须视当前机器上int所占位数而定
转义序列
换行符 \n 横向制表符 \t 报警(响铃)符 \a
纵向制表符 \v 退格符 \b 双引号 \"
反斜线 \\ 问号 \? 单引号 \'
回车符 \r 进纸符 \f
变量声明和定义
变量声明规定了变量的类型和名字,在这一点上定义与之相同。但是除此之外,定义还申请存储空间,也可能会为变量赋一个初始值。
如果想声明一个变量而非定义它,就在变量名前面添加关键字extern,而且不要显示地初始化变量。
extern int i; //声明i而非定义i int j; //声明并定义j //任何包含了显示初始化的声明即成为定义 extern double pi = 3.1416 ;//此处赋初始值抵消了extern的作用,就变成了定义
变量只能被定义一次,但是可以被声明多次。
引用
引用必须初始化,引用即别名。
引用并非对象,相反的,它只是为一个已经存在的对象所起 的另外一个名字。
可以在一条语句中定义多个引用,但是每个引用标识符都必须以&开头。// int i1 = 1024,&i1 = i1,&i2 = i1,&i3 = i1;
- const引用可用一个表达式初始化//int ia =1 ; const int res = ia * 8;
- 基类指针或引用可绑定到派生类对象
- 除以上两种情况外,其余引用都要和其绑定的对象类型严格匹配。
指针
指针与引用的差异:
- 指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以先后指向几个不同的对象
- 指针无须在定义时赋初值
指针存放对象的地址,通过取地址符&获取对象地址。
指针的值(即地址)应属下列四种状态:
- 指向一个对象
- 指向紧邻对象所占空间的下一个位置
- 空指针,意味着指针没有指向任何对象
- 无效指针,也就是上述情况之外的其他值
利用指针访问对象
使用解引用符(*)来访问指针指向的对象。
空指针
int * p1 = nullptr;//等价于 int * p1 = 0; int * p2 = 0; //直接将p2初始化为字面常量 0 //需要首先#include cstdlib int * p3 = NULL;//等价于int * p3 = 0; NULL是预处理变量,定义在头文件cstdlib中,它的值就是0 //预处理变量不属于命名空间std,它由预处理器负责管理,因此可以直接使用,而无须添加std:: //当用到一个预处理变量的时候,预处理器会自动将它替换为实际值。
指针的比较
- 任何非0指针对应的条件值都是true.
- 如果两个指针存放的地址值相同,则它们相等;反之它们不相等。
- 这里两个指针存放的地址值相同(两个指针相等)有三种可能:
- 它们都为空
- 都指向同一个对象
- 都指向了同一个对象的下一地址
void* 指针
void* 是通用指针,任何类型的指针都可以转换为void*.
不能直接操作void*指针所指的对象,因为我们并不知道这个对象到底是什么类型,也就无法确定能在这个对象上做哪些操作。
const 限定符
因为const对象一旦创建后,其值便不能更改,所以const对象必须初始化。
默认状态下,const对象仅在当前文件内有效。如果想在多个文件之间共享const对象,必须在变量的定义之前添加extern.
extern const int buffsize = 1024;
const的引用
对常量的引用,其引用的对象也必须是一个常量。
const int ci = 1024; const int &r1 = ci;//正确,引用及其对应的对象都是常量 r1 = 42; //错误,r1是对常量的引用 int &r2 = ci; //错误,试图让一个非常量引用指向一个常量对象
指针与const
指向常量的指针
const double pi = 3.14; const double *cptr = π
常量指针
指针是对象而引用不是,因此就像其他对象类型一样,允许把指针本身定为常量。常量指针(const pointer)必须初始化,而且一旦初始化完成,则它的值(也就是存放在指针中的那个地址)就不能再改变了。
把*放在const之前用以说明指针是一个常量,这样的书写隐含着一层意味,即不变的是指针本身的值而非指向的那个值:
int errNum = 0; int *const curErr = &errNum; //curErr将一直指向errNum const double pi = 3.14159; const double *const pip = π//pip是一个指向常量对象的常量指针
可以通过从右向左的方式解析该声明的含义:
离currErr最近的符号是const,意味着curErr本身是一个常量对象,下一个符号是*,意思是curErr是一个常量指针。
类似的,推断出pip是一个常量指针,它指向一个双精度浮点型常量。
顶层const与底层const
顶层const表示指针本身是个常量。
底层const表示指针所指的对象是一个常量。
详见 : P57