拿起《C++ Primer》打算重温下C++,感觉自己大二时学的c++基础还是可以,但那些基础只是c++的皮毛,一直感觉没有领悟到c++的精髓。下面会边读边记录我觉得要特别注意或者是我已经不太熟悉的知识点,写读书笔记主要是为了让自己感觉到一本书没有白读,也为了以后的温习。
第1章 开始
1.读取数量不定的输入数据:while(cin>>value)。
2.编译器无法检查逻辑错误,可以发现语法错误,类型赋值错误,未声明错误等。
第一部分 C++基础
第2章 变量和基本类型
1. 算数类型:(至少) char:1个字节; short:2个字节; int:2个字节;long:4个字节;long long:8个字节;float:6位有效数字;double:10位有效数字; 1个字=4个字节。
2.类型转换:unsigned char c = -1 //假设char占8位(0-255),c的值是255; signed char c2=256 //假设char占8位,c2的值是未定义的。总结:(1)赋给无符号类型一个超出它表示范围的值时(如负数),结果是所赋的值对该无符号类型表示数值总数(256个)取模后的余数,赋给带符号类型一个超出它表示范围的值时,结果是未定义的;(2)给无符号数加上一个负数,结果是先将负数按照(1)的方法转化成无符号数再相加; (3) for(unsigned u=10 ; u>=0 ; --u){} 这是一个死循环。
3.转义序列:如果反斜线\后面跟着的八进制数字超过3个,只有前3个与\构成转义序列,例如“\1234”表示2个字符(‘\123’和‘4’),相反\x要用到后面跟着的所有十进制数。
4.默认初始化:如果内置类型(例如int ,double等)的变量未被显示初始化,值由定义的位置决定:定义在任何函数体之外初始化为0,函数体之内则不被初始化;对于类对象而言,是否默认初始化取决于类定义,例如string类规定未显示初始化则声称空串。
5.声明和定义:extern int i ; //extern关键字表示声明而非定义i(定义会分配内存病给初值);int j ; //声明并定义j。
6.引用:int ival=0 ; int &refVal=ival ;//引用必须被初始化,以后改变refVal也会改变ival的值,但引用本身不是对象。int &refVal2=refVal ; //refVal本身不是对象不能创建引用的引用,故refVal2仍是ival的引用。另外,引用的初始值只能是对象(不能是字面量),下面是错误的写法:int &refVal3=0 ; //错误。
7.指针:int ival = 0 ; int *p = &ival ; //指针指向的是对象的地址,故要用取地址符&,另外因为引用不是对象,没有地址,故不能创建引用的指针。若要访问指针p的值,要用“*”号解引用符:例如cout<<*p;指针与引用不同点:(1)指针本身是对象,允许对指针赋值和拷贝,且可以先后指向不同对象;(2)指针无须在定义时赋值。
8.符号:&紧随类型名出现:int &refVal=ival表示声明引用;&出现在表达式中:p=&i 表示取地址符; *号紧随类型名出现:int *p表示声明指针;*号出现在表达式中:*p=i表示解引用符。 在int &r = *p中,&是声明引用,* 号是解引用符。
9.指针的定义:int* p1,p2; *号只用来修饰与它紧挨着的变量名,故p1是int指针,p2是int变量;另外int* p1和int *p1是一样的意思,只是写法的不一样而已,数据类型是int而非int*, *号只用来修饰后面的p1。
10.const与指针:1.(底层const)想要存放常量对象的地址,只能使用指向常量的指针:const int *p=&i; // 其中 i 是const变量,p不能用来改变 i 的值,例如不能 *p=100,但可以改变p本身的值(即地址),例如可以p=&j; 2.(顶层const)const指针:int *const p=&i; //其中i是非const变量,指针本身是常量,而非指向的值,不变的应该是指针本身(即地址)。
11.类型别名typedef: typedef double d,dou; //double是被取别名的类型,d和dou都是为double取的别名。
12.预处理器之头文件保护符:#define指令把一个名字设定为预处理变量,#ifdef当且仅当变量已经定义时为真,#ifndef当且仅当变量未被定义时为真,一旦检查为真,则会顺序运行直至遇到$endif,一旦检查为假,则会忽略#endif之前的所有内容,例如Sales_data.h内容如下: #ifndef SALES_DATA_H #define SALES_DATA_H #include
第3章 字符串、向量和数组
1.vector对象(以及string)的下标运算符只能用来访问已经存在的元素,不能用来添加元素。
2.迭代器:begin()表示容器的第一个元素,end()表示尾元素的下一个位置,end()实际上只是一个标记,叫做尾后迭代器 ; 一般用法:for(auto it = s.begin() ; it!=s.end() ; i++){}。如果容器为空,则begin()和end()返回的是同一个迭代器,都是尾后迭代器 ;迭代器的运算符:*iter(返回迭代器iter所指元素的值,跟指针用法一样,且iter->mem和(*iter).mem是一样的意思),item->mem(解引用iter并获取钙元素的名为mem的成员),--iter,++iter,iter1==iter2。
3.迭代器的泛型思想:for循环中使用!=而非<进行判断,因为所有标准库容器都定氮仪了==和!=,但是大多数都没有定义<,因此只要我们养成使用迭代器和!=的习惯,就不用太在意用的是哪种容器。
4.string和vector是两种最重要的标准库类型,string是一个可变长的字符序列,vector对象是一组同类型对象的容器
5.缓冲区溢出指一种严重的程序故障,主要原因是试图通过一个越界的索引访问容器内容。
6.类模板:用来创建具体类模型的模板
第4章 表达式
第五章 语句
1.try语句块和异常处理:异常检测部分-throw : throw+异常类型;例如throw runtime_error("input is error!");//runtime_error是标准库异常类型中的一种,括号里是对它的初始化。try{} catch(runtime_error err){} //try后面可以跟多个catch语句,根据括号里的异常声明类型来匹配执行不同的catch语句
2.常用异常类:exception(最常见的问题),runtime_error(只有在运行时才能检测出的问题),range(运行时错误:结果超出值域范围),overflow_error(运行时错误:计算上溢),underflow_error(运行时错误:计算下溢),logic_error(程序逻辑错误),invalid_argument(无效参数)
3.异常安全指:抛出异常后,程序能执行正确的行为。
第六章 函数
1.分离式编译:fact函数被定义在 fact.cc中, factMain.cc中创建main函数,main调用fact函数
$ CC factMain.cc fact.cc //生成 factMain.exe或a.out
$CC factMain.cc fact.cc -o main //生成main或main.exe
2.函数重载:同一作用于内,函数名字相同但形参列表不同
3.一个形参被赋予了默认值,那它后面的所有形参都必须有默认值;当一个函数有多个带有默认值的形参,但调用时有的形参想用默认值,而有的不想用默认值时,只能省略尾部的实参,尾部的使用默认值。