《从陷阱中学习C/C++》读书笔记

1、运算符优先级很容易引起问题,如a = 4<<1+1,由于<<的优先级低于+,故其执行过程为 a = 4<<(1+1);

常见的运算符优先关系:(具体参照博客

优先级

运算符

名称或含义

使用形式

结合方向

说明

1

[]

数组下标

数组名[常量表达式]

左到右

--

()

圆括号

(表达式)/函数名(形参表)

--

.

成员选择(对象)

对象.成员名

--

->

成员选择(指针)

对象指针->成员名

--

2

-

负号运算符

-表达式

右到左

单目运算符

~

按位取反运算符

~表达式

++

自增运算符

++变量名/变量名++

--

自减运算符

--变量名/变量名--

*

取值运算符

*指针变量

&

取地址运算符

&变量名

!

逻辑非运算符

!表达式

(类型)

强制类型转换

(数据类型)表达式

--

sizeof

长度运算符

sizeof(表达式)

--

3

/

表达式/表达式

左到右

双目运算符

*

表达式*表达式

%

余数(取模)

整型表达式%整型表达式

4

+

表达式+表达式

左到右

双目运算符

-

表达式-表达式

5

<< 

左移

变量<<表达式

左到右

双目运算符

>> 

右移

变量>>表达式

6

大于

表达式>表达式

左到右

双目运算符

>=

大于等于

表达式>=表达式

小于

表达式<表达式

<=

小于等于

表达式<=表达式

7

==

等于

表达式==表达式

左到右

双目运算符

!=

不等于

表达式!= 表达式

8

&

按位与

表达式&表达式

左到右

双目运算符

9

^

按位异或

表达式^表达式

左到右

双目运算符

10

|

按位或

表达式|表达式

左到右

双目运算符

11

&&

逻辑与

表达式&&表达式

左到右

双目运算符

12

||

逻辑或

表达式||表达式

左到右

双目运算符

13

?:

条件运算符

表达式1?

表达式2: 表达式3

右到左

三目运算符

14

=

赋值运算符

变量=表达式

右到左

--

/=

除后赋值

变量/=表达式

--

*=

乘后赋值

变量*=表达式

--

%=

取模后赋值

变量%=表达式

--

+=

加后赋值

变量+=表达式

--

-=

减后赋值

变量-=表达式

--

<<=

左移后赋值

变量<<=表达式

--

>>=

右移后赋值

变量>>=表达式

--

&=

按位与后赋值

变量&=表达式

--

^=

按位异或后赋值

变量^=表达式

--

|=

按位或后赋值

变量|=表达式

--

15

逗号运算符

表达式,表达式,…

左到右

--

2、c++宏定义时要对每个变量和语句加上括号,在编译之前,将宏带入语句看有没有逻辑错误,

  在c++中使用宏定义的函数尽量使用内联函数代替;

  使用宏来存储常量的尽量使用const变量代替;

  使用宏来缩短长变量名的,可以用引用来代替;

3、给宏定义命名时,要避免宏名称与系统库的定义同名。

4、将char转换为int时,一定要注意char的最高位是0还是1,一般系统中char为为有符号的,在将char转换为int时,先将char转换为unsigned char

char a = 0x9A;
int util = (int)(unsigned char)a;

  将int转换为char时,如果系统默认char为unsigned char,则下面会出现问题:

char c;
while((c = getchar())!=EOF){ //如果char是unsigned char则EOF(-1)会转换为(unsigned char)255
putchar(c);
}

解决方法是

int c; //去除int转换为char的强制转化
while((c = getchar())!=EOF){
putchar(c);
}

对于变量的强制转换,需要注意类型的截断和扩展。

一定要注意有符号int和无符号int比较的后果:

#include <iostream>
#include <vector>
using namespace std; int main(){
vector<int> a;
a.push_back();
a.push_back();
int i = -;
if(i< a.size()) cout<<"True"<<endl; ////由于size()返回的是size_t,其是unsigned int此时i会转换成unsigned int,
else cout<<"False"<<endl;
return ;
}

在位域结构体中,注意结构体变量类型

#include <iostream>
#include <vector>
using namespace std; struct data{
int flag : ; //注意这代表符号位,取值范围为0或-1
int other: ;
};
int status(){
return ;
} int main(){
struct data test;
test.flag = ; //返回值1赋给flag时会出现溢出,
cout<<test.flag;
}

解决方法是将结构体中的变量变成unsigned int

5、浮点数比较时,一般比较他们的差值在一定范围内

6、关于常量指针和指针常量:

  int *const px ;  //指真本身是常量,它指向的地址是不可改变的,但地址里的内容可以通过指针改变。

  const int *py;  // 指针指向的是常量,它不能指向变量,它指向的内容不能改变,不能通过指针来修改它指向的内容,但指针本身不是常量,它自身的值可以改变。

7、关键字extern可以置于变量和函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量或函数时在其他模块中寻找定义。

8、对结构体进行赋值时,建议具体到结构体的成员变量名。

struct rectangle
{
int length;
int width;
} struct rectangle rect ={rect.length = , rect.width = };

9.关于cin>>和getline混用导致的奇怪问题

#include <iostream>
#include <vector>
using namespace std; int main(){
int num;
string str;
cin >> str; //读取到连续的字符串后,立即停止,用户按下回车键时,"\n"留在输入流中
cin.ignore(); //解决方法用cin.ignore()清除留在输入流中的换行符
getline(cin,str); //getline遇到换行符结束
cout<<num << " "<<str<<endl;
}
上一篇:.NET软件汉化小实例


下一篇:bzoj 1031 [JSOI2007]字符加密Cipher