Primer C++第五版 读书笔记(一) (如有侵权请通知本人,将第一时间删文) 1.1-2.2 章节 关于C++变量初始化: 初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,以一个新值来替代. 定义一个名为a的int变量并初始化为0,有以下4种方法: int a = 0; int a = {0}; // 列表初始化 int a{0}; // 列表初始化 int a(0); 当列表初始化方法用于内置类型的变量时,如果初始值存在信息丢失的风险,则编译器将报错. 示例: long double ld = 3.1415926536; int a{ ld }, b{ ld }; // error C2397 从"long double"转换到"int"需要收缩转换 int c(ld), d = ld; // warning C4244: "初始化": 从"long double"转换到"int",可能丢失数据 定义变量的错误示范: double salary = wage = 9999.99; // error:没定义变量 wage std::cin >> int input_value; // 不允许 下列变量的初始值是什么? string global_str; // 全局变量,值为"" int global_int; // 全局变量,值为 0 int main() { int local_int; // 局部变量,是未定义状态,无意义数据 string local_str; // 哪怕它是局部变量,它也是string定义的,值为"" } 未初始化的变量可能引发运行时的故障. 建议初始化每一个内置类型的变量.虽然并非必须,但如果我们不能确保初始化后程序安全,那么这么做不失为一种简单可靠的方法. 注意: 变量只可以被定义一次,但可被声明多次. 如果想声明一外变量而非定义它,可在变量名前添加关键字 extern , 而不要显示地初始化变量,示例如下: extern int i; // 声明变量 i 而非定义它 int j; // 声明并定义变量 j 任何包含了显示初始化的声明即成为定义.我们能给由extern关键字标记的变量赋一个初始值,但这么做就抵消了extern的作用. extern语句如果包含了初始值就不再是声明,而变成了定义: extern double pi = 3.1415; // 定义 在函数体内部,如果试图初始化一个由extern关键字标记的变量,将引发错误. ============================================================================================ 2.3 C++复合类型: 引用: 引用(reference)为对象起了另外一个名字,引用类型引用(refers to)另外一种类型. int ival = 1024; int &refVal = ival; // refVal指向ival(是ival的另一个名字) int &refVal2; // 错误!!引用必须被初始化 引用即别名:引用并非对象,相反的,它只是为一个已经存在的对象所起的另外一个名字. 为引用赋值,实际上是把值赋给了与引用绑定的对象.获取引用的值,实际上是获取了与引用绑定的对象的值. 同理,经引用作为初始值,实际上是以与引用绑定的对象作为初始值. 因为引用本身不是一个对象,所以不能定义引用的引用. 绝大多数情况 下,引用的类型都要和与之绑定的对象严格匹配.而且,引用只能绑定到对象上,而不能与字面值或某个表达式的计算结果绑定在一起. int &refVal4 = 10; // 错误:引用类型的初始值必须是一个对象. const int &refVal4 = 10; // 正确 double dval = 3.14; int &reva l5 = dval; // 错误:引用类型要与与之绑定的对象严格匹配! 指针: 指针(pointer)是指向另外一种类型的复合类型. 指针与引用相比有很多不同点(重点): 0.引用是已经存在的对象的另一个名称,而指针是一个对象,它遵循自己的使用规则. 1.指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以先后指向几个不同的对象. 2.指针无须在定义时赋初值,和其他内置类型一样,在块作用域内定义的指针,如果没有被初始化,也将拥有一个不确定的值.引用在定义时就必须初始化. 3.最大不同:引用本身并非一个对象,一旦定义了引用,就无法令其再绑定到另外的对象,之后每次使用这个引用都是访问它最初绑定的那个对象. int *ip1, *ip2; // ip1 和 ip2 都是指向 int 型对象的指针 double dp, *dp2; // dp2 是指向 double 型对象的指针,dp 是 double 型对象. 获取对象的地址: 指针存放某个对象的地址,想要获取该地址,需要使用取地址符(&): int ival = 42; int *p = &ival; // p 存放变量ival的地址,或者说p是指向变量ival的指针. 示例: double dval; double *a = &dval; // 正确:初始值是double型对象的地址 double *a2 = a; // 正确:初始值是指向double开进对象的地址 int * b = a; // 错误:指针b的类型与指针a的类型不匹配! int * b2 = &vdal; // 错误:试图把double型对象的地址赋给int型指针 因为在声明语句中指针的类型实际上被用于指定它所指向对象的类型,所以二者必须匹配.如果指针指向了一个其他类型的对象,对该对象的操作将发生错误. 指针值: 指针的值(即地址)应属下列4种状态之一: 1.指向一个对象 2.指向紧邻对象所占空间的下一个位置 3.空指针,意味着指针没有指向任何对象 4.无效指针,也就是上述情况之外的其他值. 试图拷贝或以其他方式访问无效指针的值都将引发错误.编译器并不负责检查此类错误,这一点和试图使用未经初始化的变量一样.因此程序员必须清楚任意给定的指针是否有效. 利用指针访问对象: 如果指针指向了一个对象,则允许使用解引用符(*)来访问该对象: int ival = 42; int *p = &ival; // p存放着变量ival的地址,或者说p是指向变量ival的指针. cout << *p; // 由符号*得到指针p所指向的对象,输出42. 对指针解引用会得到所指的对象,因此如果给解引用的结果赋值,实际上也就是给指针所指的对象赋值: *p = 0; cout<<*p; // 输出0. 解引用操作仅适用于那些确实指向了某个对象的有效指针. 空指针: 空指针不指向任何对象,在试图使用一个指针之前可先检查它是否为空