这个标题不够犀利,不少人看到第一反应肯定是——“这我知道啊”。但是很多人肯定写过如下的代码:
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main()
{
string s = "abcde";
for(int i = 0; i < s.size(); ++i) {
s[i] = toupper(s[i]);
}
cout<<s<<endl;
}
这个例子是将所有的小写字母变成大写字母,很正常。但是这种编程习惯有个隐藏的风险,再来看下面这段代码,这段代码的作用是,遍历容器v,然后每次将长度不大于range的字符串打印出来。range会逐渐减小。你觉得输出的结果是什么?
#include<cstring>
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main()
{
vector<string> v;
v.push_back("abc");
v.push_back("ab");
v.push_back("a");
v.push_back("ab");
v.push_back("abc");
int range = 3;
for(int i = 0; i < v.size(); ++i, --range) {
if(v[i].size() <= range) {
cout<<v[i]<<endl;
}
}
}
正常而言,我们期望它的输出如下:
abc
ab
a
但实际输出是:
abc
ab
a
abc
是不是有人觉得自己不会写出这样的代码,即便在其它地方也不会出现非这样写不可的情况。但事实是,你写了都不知道……我今天做leetcode的“text justification”用了很久才发现布尔表达式里面计算出了非常奇怪的结果,浪费了很多时间。
上面代码的问题在于用一个无符号unsigned值与一个有符号的int作比较,当range变为-1的时候,在表达式v[i].size() <= range中,它会被转换成一个无符号的数,因此会变成一个很大的正数,程序的输出就和原来期望不复合了。
当然也不是说永远不能让无符号和有符号的数比较,但是你在这么写的时候,一定要知道自己在做什么,并且知道这样做是没有问题的。如果用Visual Studio,我印象中其对于这种比较是会出警告的,但是很多编译器就不会警告。问题是即便我用Visual Studio,也会自动忽略那段编译警告,Xcode就压根没有警告……
C++用得比较多,但是我越用越觉得自己好像就没怎么掌握这门语言