不同平台下atoi函数实现的差别

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的实现会有一些差异,而这些差异可能就会引发很严重的后果,所以如果要编写跨平台的程序,一定要慎重慎重再慎重。

时间: 2024-08-17 19:52:28

不同平台下atoi函数实现的差别的相关文章

.net平台下C#socket通信(中)

本文主要讲述: 1.正常通信中握手建立 2.一对多的通信 3.发送接收数据格式转换 4.资源释放 5.开启并保持服务监听 1.握手建立正常的通信通道 项目需要通信的双方(假设是一个上位机.一个下位机)之间需要建立一个稳定的通道,以便进行通信.本项目中具体操作是:上位机作为服务器,下位机作为客户端,同时制定通信协议.上位机首先打开监听等待建立通道,下位机主动连接上位机后发送连接成功的信息到上位机,上位机根据通信协议发送数据到下位机,此时通道已经建立.但为了保险起见(同时遵循三次握手),客户端再次发

wchar_t内置还是别名(wchar_t在windows下是16整数的别名,在linux等平台下是32位整数的别名。MSVC2008开始默认是/Zc:wchar_t)

接前一篇C++ ABI之名字改编(以Qt为例),继续看看C++名字改编相关的问题. 问题 MSVC 有一对选项/Zc:wchar_t- 与 /Zc:wchar_t控制wchar_t 于是 wchar_t 可以是 unsigned short 或 __wchar_t(称为原生类型?) 的别名 两个东西混用会怎么样? 首先考虑,会混用么?,是杞人忧天么? 由于 Qt 为 MSVC 提供的二进制包采用的前者/Zc:wchar_t-.考虑: 如果你编译自己的Qt程序时,启用了后者,会怎么样? 如果Qt程

[转帖]Android平台下OpenGL初步

原文请看 Android平台下OpenGL初步 本文只关注于如何一步步实现在Android平台下运用OpenGl. 1.GLSurfaceView GLSurfaceView是Android应用程序中实现OpenGl画图的重要组成部分.GLSurfaceView中封装了一个Surface.而android平台下关于图像的现实,差不多都是由Surface来实现的 2.Renderer 有了GLSurfaceView之后,就相当于我们有了画图的纸.现在我们所需要做的就是如何在这张纸上画图.所以我们需

[转]Windows平台下Makefile学习笔记

Windows平台下Makefile学习笔记(一) 作者:朱金灿 来源:http://blog.csdn.net/clever101 决心学习Makefile,一方面是为了解决编译开源代码时需要跨编译平台的问题(发现一些开源代码已经在使用VS2010开发,但我还没安装VS2010,我想在VS2008下编译这些代码):另一方面源码在服务器端编译的话,使用IDE的方式编译还是不太方便. 本文主要分为三部分:第一部分讲述namke工具使用makefile的用法:第二部分讲述makefile的主要语法:

浅谈Windows平台下C++调用静态链接库的方式

浅谈Windows平台下C++调用静态链接库的方式 1. 什么是静态链接库?为什么要用静态链接库? 维基百科上关于静态库的解释是这样的:在计算机科学里,静态库(英语:Static library, Statically-linked library),或称静态库,是一个外部函数与变量的集合体.静态库的文件内容,通常包含一堆程序员自定的变量与函数,其内容不像动态链接库那么复杂,在编译期间由编译器与连接器将它集成至应用程序内,并制作成目标文件以及可以独立运作的可执行文件. 由上面的解释可以很清楚的看

.net平台下C#socket通信(转)

上篇.net平台下C#socket通信(上)介绍了socket通信的基本原理及最基本的通信方式.本文在此基础上就socket通信时经常遇到的问题做一个简单总结,都是项目中的一些小问题,拿来此处便于下次使用,同时对在使用socket时出现些许问题的同仁们多一个粗浅建议.不足之处请提出,谢谢. 本文主要讲述: 1.正常通信中握手建立 2.一对多的通信 3.发送接收数据格式转换 4.资源释放 5.开启并保持服务监听 1.握手建立正常的通信通道 项目需要通信的双方(假设是一个上位机.一个下位机)之间需要

最老程序员创业开发实训4---IOS平台下MVC架构

在前面几篇文章中,我们大致研究了一下,在Android平台,以应用开始时的Splash页面为例,讲述了怎样利用MVC架构来实现这一简单功能,有可能有朋友认为,对于这样简单的功能,采用MVC架构有些过了.但是,如果需求变为,需要根据时间.地点等,显示从服务器上下载的图片,那么我们所采用的架构,就具有一定的优势了. 下面,我们将讲述在IOS平台怎样实现相同的功能.我们知道在IOS平台上开发原生应用,有两种技术可供选择,即Objective-C或Swift.如果对于找工作而言,当前最好的选择依然是Ob

MAC平台下Xcode配置使用OpenCV的具体方法 (2016最新)

1.序言: 1.1 背景 本人小白一枚,不过因为最近在从事机器视觉方面的工作,所以接触到OpenCV. 因为工作需求,本人要在MAC端使用OpenCV实现一些视觉功能,配置环境成了最大的阻碍,网上查了很多相关资料和博客,都因为版本环境问题屡试屡败,不过经历重重尝试,笔者最终还是配置成功并运行了自己的源码.当然成功的关键还是因为笔者站在了巨人的肩膀上,借鉴了很多网上的教程,为了不误导大家配置的过程,参考文章的地址统一放在文章里,望各位大大看见之后能够理解,废话不说进入正题. 1.2 环境说明 如果

【C语言】模拟实现atoi函数

atoi(表示 ascii to integer)是把字符串转换成整型数的一个函数. atoi()函数会扫描参数 nptr字符串,跳过前面的空白字符(例如空格,tab缩进等,可以通过isspace( )函数来检测),直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回.如果 nptr不能转换成 int 或者 nptr为空字符串,那么将返回0 我们在模拟实现atoi函数时,要注意以下几点: 1.字符串之前的空白问题 2.正负号 3.字符串为空时 4.