我们首先看一段程序:
#include <iostream>
#include <string>
using namespace std;
int main( void )
{
string s1( "123456789" );
size_t x = s1.find_first_of( '0', 0 );
if (x == string::npos)
{
cout << "not find" << endl;
}
else
{
cout << s1.at( x ) << endl;
}
//------------------------------------
x = s1.find_first_of( '5', 0 );
if (x == string::npos)
{
cout << "not find" << endl;
}
else
{
cout << s1.at( x ) << endl;
}
system( "PAUSE" );
return EXIT_SUCCESS;
}
输出为:
可以看出:返回值与string::npos比较,相等则没找到
那么我们开始关注npos:
npos 是一个常数,用来表示不存在的位置,取值由实现决定,一般是-1。
npos 是这样定义的:
static const size_type npos = -1;
static const size_type npos = -1;
int idx = str.find("abc");
if (idx == string::npos)
上述代码中,idx的类型被定义为int,这是错误的,即使定义为 unsigned int 也是错的,它必须定义为 string::size_type。
因为 string::size_type (由字符串配置器 allocator 定义) 描述的是 size,故需为无符号整数型别。因为缺省配置器以型别 size_t 作为 size_type,于是 -1 被转换为无符号整数型别,npos 也就成了该型别的最大无符号值。
不过实际数值还是取决于型别 size_type 的实际定义。不幸的是这些最大值都不相同。事实上,(unsigned long)-1 和 (unsigned short)-1 不同(前提是两者型别大小不同)。因此,比较式 idx == string::npos 中,如果 idx 的值为-1,由于 idx 和字符串string::npos 型别不同,比较结果可能得到 false。
要想判断 find() 的结果是否为npos,最好的办法是直接比较:
if (str.find("abc") == string::npos) { ... }
在网上也有关于这方面的经验:
将函数返回一个值之后再做判断与直接判断结果截然不同。
在不使用临时变量赋值的情况下,本来应该运行到A的代码直接跳转到B了
///int r = translateToLower(str).find("text");
if( translateToLower(str).find("text") <0 ) /// if( r <0 )
{ ///{
...... /// A ...... A 运行到此
} ///}
...... /// B 直接运行到此 /// ...... /// B
我们一起调试之后确认其描述不虚。这似乎颠覆了我们对函数返回值、临时变量的理解,真是不可思议。
困惑之下,我还是隐隐觉得这种怪现象应该与模板库find函数的使用有关。
最终阅读了文档之后我们恍然大悟。我觉得有趣将其记录于此。
文档里有这样的定义:
find函数在找不到指定值得情况下会返回string::npos。
string::npos
static member constant
static const size_t npos = -1;
Maximum value for size_t
问题就在这:
将一个负数付给无符号数,这是一个非常聪明的技巧,正如文档所言,它是无符号数size_t的最大值。
可是将这个返回值付给int 型变量r的时候,它却因为超出了int的上限被转换成了负数-1,所以调试后想当然得认为函数返回值<0成立。
殊不知在不经过转换的情况下,函数的返回值作为一个无符号数却是远远大于0的。由此产生了让我们一撇之下感到不可思议的事情。
这不正是书本里三番五次强调的无符号数陷阱么?没想到居然在这种情况下遭遇到了。
正确的做法应该是:
if( translateToLower(str).find("text") != string::npos )