《从陷阱中学习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(1); a.push_back(2); int i = -1; if(i< a.size()) cout<<"True"<<endl; ////由于size()返回的是size_t,其是unsigned int此时i会转换成unsigned int, else cout<<"False"<<endl; return 0; }
在位域结构体中,注意结构体变量类型
#include <iostream> #include <vector> using namespace std; struct data{ int flag : 1; //注意这代表符号位,取值范围为0或-1 int other: 31; }; int status(){ return 1; } int main(){ struct data test; test.flag = 1; //返回值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 = 4, rect.width = 2};
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; }

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号