moonfighting

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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是

Input:"2147483648" -2147483648
Output:["2147483648"]
Expected:[]
输入的字符串是"2147483648", 目标值-2147483648,期望输出是[],而我的输出则是["2147483648"],奇怪的是我在vs2010上跑这个test case的时候得到的是正确的结果,而在leetcode上结果就不对,自己简单的分析了一席,出错的可能在于有一些函数在两个平台下的实现不同,导致最终结果不同。
首先看这个输入的字符串,稍微有点敏感性的程序员都会发现这个字符串作为一个int型变量已经溢出了,那么当atoi转换一个已经溢出的字符串时是如何处理的?这个似乎没有统一的规定,也就是说各个平台处理的方式可能不一样。没关系,我们看下源码就知道。
首先看vs2010中的atoi对溢出的处理
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的实现会有一些差异,而这些差异可能就会引发很严重的后果,所以如果要编写跨平台的程序,一定要慎重慎重再慎重。

 

 

 
posted on 2015-09-24 14:08  moonfighting  阅读(539)  评论(0编辑  收藏  举报