atoi是一个比较常用的字符串转换成整数的函数,原型是
int atoi(const char *str)
输入一个字符串,返回一个int型变量,但是它的实现在不同平台下不尽相同,今天做leetcode的时候就遇到了这个问题。
leetcode的这道题是这样的:
Expression Add Operators
Given a string that contains only digits 0-9
and a target value, return all possibilities to add binary operators (not unary) +
, -
, or *
between the digits so they evaluate to the target value.
Examples:
"123", 6 -> ["1+2+3", "1*2*3"] "232", 8 -> ["2*3+2", "2+3*2"] "105", 5 -> ["1*0+5","10-5"] "00", 0 -> ["0+0", "0-0", "0*0"] "3456237490", 9191 -> []
给一个只含有0-9字符的字符串和一个目标值,在字符串中添加 + / * 三种符号,使字符串形成的计算表达式的值和目标值相同,返回所有可能的结果。
这道题是常见的用递归可以解决的题,我的代码是这样的
class Solution {
public:
vector<string> addOperators(string num, int target) {
vector<string> result;
if(num.empty())
return result;
string expression = "";
int last_result = 0;
dfs(result, expression, num, '+', 0, 0, target);
return result;
}
void dfs(vector<string> &result, string &expression, string &number_str, char pre_oper, long long val, long long pre_num, long long target)
{
int len = number_str.size();
int num = atoi(number_str.c_str());
if(number_str.empty())
{
if(val + pre_num == target)
{
result.push_back(expression);
return;
}
}
for(int i = 1; i <= len; i++)
{
string num_left_str = number_str.substr(0, i);
string num_right_str = number_str.substr(i);
long long num_left = atoi(num_left_str.c_str());
long long new_pre_num = 0;
expression += num_left_str;
long long new_val = 0;
if(pre_oper == '*')
{
new_pre_num = pre_num * num_left;
new_val = val;
}
else
{
new_pre_num = pre_oper == '+' ? num_left : -num_left;
new_val = val + pre_num;
}
if(num_right_str.empty())
dfs(result, expression, num_right_str, ' ', new_val, new_pre_num, target);
else
{
expression.push_back('+');
dfs(result, expression, num_right_str, '+', new_val, new_pre_num, target);
expression.back() = '-';
dfs(result, expression, num_right_str, '-', new_val, new_pre_num, target);
expression.back() = '*';
dfs(result, expression, num_right_str, '*', new_val, new_pre_num, target);
expression.pop_back();
}
expression.resize(expression.size() - i);
if(num_left_str == "0")
return;
}
}
};
这里我用atoi来将字符串转换为数字,但是在提交之后出现了wrong answer, 出错的test case是
else if ( (flags & FL_OVERFLOW) ||
( !(flags & FL_UNSIGNED) &&
( ( (flags & FL_NEG) && (number > -LONG_MIN) ) ||
( !(flags & FL_NEG) && (number > LONG_MAX) ) ) ) )
{
/* overflow or signed overflow occurred */
errno = ERANGE;
if ( flags & FL_UNSIGNED )
number = ULONG_MAX;
else if ( flags & FL_NEG )
number = (unsigned long)(-LONG_MIN);
else
number = LONG_MAX;
}
可以看到,当转换得到的数溢出时,函数返回LONG_MAX, LONG_MIN 或 ULONG_MAX,总而言之,返回最大值或最小值。
所以当输入“2147483648”时,得到的整数是2147483647,和目标值不同,最终结果为空。
而我们再看看leetcode用的atoi函数是如何处理的?由于没法看到源码,所以我改了一下代码,直接输出结果来看
vector<string> addOperators(string num, int target) {
vector<string> result;
if(num.empty())
return result;
string expression = "";
int last_result = 0;
int a = atoi(num.c_str()); //得到转换后的结果并输出
cout << a << endl;
dfs(result, expression, num, '+', 0, 0, target);
return result;
}
Your stdout那一栏就是输出的a的值
可以看到当输入字符串为“2147483648”时,调用atoi得到的整数是-2147483648,正好和目标值相同,因此系统就将“2147483648”当作了结果。
因为这一个函数的实现差异,导致了最终不同平台上的不同结果。
总结:对于C++中的某些函数,linux下和windows的实现会有一些差异,而这些差异可能就会引发很严重的后果,所以如果要编写跨平台的程序,一定要慎重慎重再慎重。