c++ primer (5)1

第一章

1.包含来自标准库的头文件用<>,不属于标准库用""。

2.默认情况,读cin会刷新cout;程序非正常终止时也会刷新cout。

3.默认情况,cerr不缓冲,cerr通常用于输出错误信息或其他不属于程序正常逻辑的输出内容。

4.默认情况,clog缓冲,clog通常用于报告程序的执行信息,存入一个日志文件中。

第二章

1.算术表达不要用char,char在一些机器上是有符号的,在一些机器上是无符号的;如要使用一个不大的整数,明确指定是signed char还是unsigned char。

2.当我们赋给无符号类型一个超过它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。

比如8bit的unsigned char表示0到255,则unsigned char c=-1  //实际c=-1+256=255

3.当我们赋给带符号类型一个超过它表示范围的值时,结果是未定义的(undefined)。此时程序可能继续工作,可能崩溃,可能生成垃圾数据。

在某些情况或某些编译器下,含有无法预知行为的程序能正确执行,但我们无法保证同样一个程序在别的编译器下能正常工作,甚至已经编译过的代码再次执行也可能会出错。此外,不能认为这样的程序对一组输入有效,对另一组输入就一定有效。

4.当表达式里既有带符号类型又有无符号类型,带符号数会自动地转换成无符号数。

例如:int a=-1,unsigned b=1,a*b结果是4294967295

5.以0开始的数表示8进制,以0x或0X开头的数表示16进制。以下都表示数值20:

20 /*十进制*/  024/*八进制*/  0x14/*十六进制*/

6.默认情况下,十进制字面值是带符号数,八进制和十六进制字面值既可能是带符号也可能是无符号。

7.如果两个字符串字面值位置紧邻且仅由空格、缩进和换行符分隔,它们实际上是一个整体。

std::cout<<"something is wrong with my head, "

      "and i am try my best to solve it"<<endl;

8.泛化的转义序列,其形式是\x后紧跟1个或多个十六进制数字,或者\后紧跟1个,2个,3个八进制数字。\115和\x4d都表示自负M。

std::cout<<"hi \x4dO\115!";  //输出hi MOM!。

如果\后跟的八进制数超过3个,只有前3个数字与\构成转义序列,\1234表示两个字符。\x要用到后面的所有数字,\x1234表示一个字符。

9.指定字面值的类型,如后缀中有U或u,字面值类型从unsigned int,unsigned long和unsigned long long 中选能匹配的空间最小的一个,如后缀中有L或l,字面值类型至少是long,如有LL或ll,字面值将是long long和unsigned long long中的一种。

L'a'  //wchar_t类型a

u'a'  //char16_t

U'a'  //char32_t

u8'a'  //char

42ULL(ull,Ull,uLL)  //unsigned long long

42l(L)  //long

1e-3f(F)  //float

3.14l(L)  //long double  

10.以下初始化等价:

int a=0; int a={0}; int a(0); int a{0};

如果使用列表初始化且初始值存在丢失信息的风险,编译器将报错:

double b=3.14; int a{b},c={b};  //wrong int d(b),e=b;  //right

11.默认初始化。内置类型未被显示初始化,它的值由定义的位置决定。定义于任何函数体之外的变量被初始化为0,定义在函数体之内的将不被初始化,访问将引发错误。

每个类各自决定其初始化对象的方式,是否允许不经显示初始化就定义对象也由类自己决定。

12.声明只规定变量的类型和名字,定义除此之外还申请存储空间,也可能为变量赋初值。想声明一个变量而非定义它,就在变量名前缀加关键字extern,而且不要显示地初始化变量:

extern int i;  //声明i而非定义i

int j;  //声明j并定义j

给由extern标记的变量赋初值就抵消了extern的作用:

extern int d=0;  //定义

在函数内部,试图初始化一个extern标记的变量将引发错误。

在多个文件中使用同一个变量,只能在一个文件中定义,其他文件中都要且只能声明,不能重复定义。

13.标识符必须以字母或下划线开头,用户自定义的标识符中不能出现两个连续的下划线,也不能以下划线紧邻大写字母开头。定义在函数体外的标识符不能以下划线开头。

变量名一般小写,如index;自定义类名一般以大写字母开头,如Sales_item;多个单词组成中间用下划线,如student_loan,不要写成studentloan。

14.在函数体内使用::a表示全局作用域里的变量a。

15.“引用”指“左值引用”,引用必须被初始化,引用是一个已经存在的对象的另一个名字,与它的初始值绑定在一起。引用不是对象,不能定义引用的引用:

int ival=1024;  

int &refval=ival;  //refval指向ival,是ival的一个别名

refval=2;  //把2赋值给refval指向的对象,即ival

int ii=refval;  //与ii=ival执行结果一样

int &refval2=refval;  //refval2绑定到了与refval绑定的对象上,这里是绑定到ival上

int &refval3=10;  //错误,引用类型的初始值必须是一个对象

double dval=3.14;

int &refval=dval;  //错误,类型必须为int

15.指针是对象,允许赋值和拷贝,无须定义时赋初值。因为引用不是对象,没有实际地址,所以不能定义指向引用的指针。

对指针解引会得出所指的对象,因此如果给解引的结果赋值,实际上是给指针指向的对象赋值,解引用操作只适用于那些确实指向了某个对象的有效指针。

16.生成空指针:

int *p1=nullptr;  //nullptr可以被转换成任意其他的指针类型(最好的方法)

int *p2=0;

int *p3=NULL;  //NULL是预处理变量,在头文件cstdlib中定义,值为0。预处理变量不属于命名空间std,它由预处理器负责管理(尽量避免)

把int变量直接赋值给指针是错误的操作,即使int变量的值恰好等于0也不行

int zero=0;

int *pi=zero;  //错误

17.指向指针的指针:

int ival=1024;

int *p=&ival;  //p指向一个int型的数

int **pi=&p;  //pi指向一个int型的指针

指向指针的引用:(引用不是对象,不能定义指向引用的指针,但指针是对象,可以定义指向指针的指针和引用)

int i=2;

int *p;  //p是一个int型指针

int *&r=p;  //r是一个对指针p的引用

r=&i;  //r引用了一个指针,因此给r赋值&i就是令p指向i

*r=0;  // 解引用r得到i,也就是p指向的对象,将i的值改为0了

(理解r从右往左读,&表明r是一个引用,*表明r引用的是一个指针,引用是别名,r表示指针p,所以r=&i后p=&i)

18.默认情况下,const对象仅在文件内有效,当在多个文件出现了同名的const变量时,等同于在不同文件中分别定义了独立的变量。

要想只在一个文件中定义const,而在其他多个文件中声明并使用它,需对const变量不管声明还是定义都使用extern:

extern const int a=10;  //在file.cc中,定义并初始化了一个常量,能被其他文件使用

extern const int a;  //在file.h中,与file.cc中定义的a是同一个

19.一般情况下,引用的类型必须与其所引用对象的类型一致。一种例外是初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果可以转换成引用的类型即可:

double d=3.14;

const int &a=d;

编译器会把上述代码转换成如下:

const int temp=d;

const int &a=temp;  //即a绑定到了一个临时量对象,如果a不是常量,就会改变a的值,从而改变临时变量的值,无意义

20.和常量引用一样,指向常量的指针可以指向一个非常量:

const double pi=3.14;

const double p2=3.15

const double *ptr=&pi;

*ptr=42;  //错误

ptr=&p2;  //正确,可以改变ptr指向的对象

常量指针表示指针本身不能变,即存放在指针中的地址不能变:

int e=0;

int *const c=&e;  //c将一直指向e

*c=0;  //正确,因为e非常量,所以可以通过c去修改e的值

要区分变量是指向常量的指针还是常量指针,有效的方法是前面说的从右向左阅读。

21.顶层const表示任意的对象是常量,底层const与复合类型的基本类型部分有关(如表示指针所指的对象是一个常量):

22.常量表达式指在编译过程就能得到计算结果的表达式:

const int sz=get_size();  //sz不是常量表达式,因为它是运行时确定的

允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式,声明为constexpr的变量必须用常量表达式初始化:

constexpr int sz=get_size();  //只有当get_size()是constexpr函数时才是正确的声明

在constexpr声明中定义指针,仅对指针有效,与指针所指对象无关:

const int *p=nullptr;  //p是一个指向常量的指针

constexpr int *q=nullptr;  //q是一个指向整数的常量指针,即constexpr把它所声明的对象置为了顶层const

constexpr指针的初始值必须是nullptr或者0,或者是存储于某个固定地址中的对象:

int j=0;

constexpr int i=42;

//i和j都必须定义在函数体外

constexpr const int *p=&i;

constexpr int *q=&j;

23.类型别名:

typedef double wage;  //wage是double的同义词

typedef wage base,*p;  //base是double的同义词,p是double*的同义词

using s=sale_item;  //s是sale_item的同义词

在使用了类型别名的声明语句中,不能把类型别名替换成它本来的样子理解该语句:

typedef char *ps;

const ps p=0;  //p是常量指针,const修饰ps,而ps是指针

const char * p=0;  //p是指向const char的指针,const修饰*p,而*p是指针的解引用,即p所指对象的值

24.auto定义的变量必须有初始值,由编译器去分析表达式所属的类型:

auto item=v1+v2;  //item初始化为v1和v2相加的结果

auto i=0,*p=&i;  //正确,类型相同

auto sz=0,pi=3.14;  //错误,类型不同

int i=0,&r=i;

auto a=r;  //a是一个整数(r是i的别名,而i是一个整数)

auto会忽略顶层const,保留底层const:

const int ci=i, &cr=ci;

auto b=ci;    //b是一个整数(ci的顶层const被忽略)

auto c=cr;    //c是一个整数(cr是ci的别名,ci本身是一个顶层const)

auto d=&i;    //d是一个整型指针(整数的地址就是指向整数的指针)

auto e=&ci;    //e是一个指向整数常量的指针(对常量对象取地址是一种底层const)

如果希望推断出的auto类型是一个顶层const,需要明确指出:

const auto f=ci;    //ci的推断类型是int,f是const int

还可以将引用的类型设为auto,设定一个类型为auto的引用时,初始值中的顶层常量属性仍然保留:

auto &g=ci;    //g是一个整型常量引用,绑定到ci

auto &h=42;    //错误,不能为非常量引用绑定字面值

const auto &j=42;    //正确,可以为常量引用绑定字面值

一条语句定义多个变量时,*和&只从属于某个声明符,而非基本数据类型的一部分:

auto k=ci; &l=i;    //

auto &m=ci,*p=&ci;    //m是对整型常量的引用,p是指向整型常量的指针

auto &n=i,*p2=&ci;    //错误,i的类型为int而&ci的类型时const int

 25.decltype用于希望从表达式的类型推断出要定义的变量的类型,但是又不希望用该表达式的值初始化变量:

decltype(f()) sum=x;    //sum的类型就是函数f的返回类型

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

const int ci=0,&cj=ci;

decltype(ci) x=0;    //x的类型是const int

decltype(cj) y=x;    //y的类型是const int&,y绑定到变量x

decltype(cj) z;    //错误,z是一个引用,必须初始化
int i=42,*p=&i,&r=i;  

decltype(r+0) b;    //正确,加法的结果是int

decltype(*p) c;    //错误,c是int&,必须初始化

r是引用,decltype(r)的结果是引用类型,想让结果是r所指的类型,可以把r作为表达式的一部分,如r+0。

如果表达式的内容是解引用操作,decltype将得到引用类型,解引用指针将得到指针所指的对象。

另外,如果decltype的表达式是加上了括号的变量,结果将是引用:

decltype((i)) d;    //错误,d是int&

decltype(i) e;    //正确,e是int

你可能感兴趣的:(Prim)