题目描述

输入一个由数字组成的字符串,把它转换成整数并输出。例如:输入字符串"123",输出整数123。

给定函数原型int StrToInt(const char *str) ,实现字符串转换成整数的功能,不能使用库函数atoi。

分析与解法

本题考查的实际上就是字符串转换成整数的问题,或者说是要你自行实现atoi函数。那如何实现把表示整数的字符串正确地转换成整数呢?以"123"作为例子:

  • 当我们扫描到字符串的第一个字符'1'时,由于我们知道这是第一位,所以得到数字1。
  • 当扫描到第二个数字'2'时,而之前我们知道前面有一个1,所以便在后面加上一个数字2,那前面的1相当于10,因此得到数字:1*10+2=12。
  • 继续扫描到字符'3','3'的前面已经有了12,由于前面的12相当于120,加上后面扫描到的3,最终得到的数是:12*10+3=123。

因此,此题的基本思路便是:从左至右扫描字符串,把之前得到的数字乘以10,再加上当前字符表示的数字。

思路有了,你可能不假思索,写下如下代码:

int StrToInt(const char *str)
{
int n = 0;
while (*str != 0)
{
int c = *str - '0';
n = n * 10 + c;
++str;
}
return n;
}

显然,上述代码忽略了以下细节:

  1. 空指针输入:输入的是指针,在访问空指针时程序会崩溃,因此在使用指针之前需要先判断指针是否为空。
  2. 正负符号:整数不仅包含数字,还有可能是以'+'或'-'开头表示正负整数,因此如果第一个字符是'-'号,则要把得到的整数转换成负整数。
  3. 非法字符:输入的字符串中可能含有不是数字的字符。因此,每当碰到这些非法的字符,程序应停止转换。
  4. 整型溢出:输入的数字是以字符串的形式输入,因此输入一个很长的字符串将可能导致溢出。

上述其它问题比较好处理,但溢出问题比较麻烦,所以咱们来重点看下溢出问题。

一般说来,当发生溢出时,取最大或最小的int值。即大于正整数能表示的范围时返回MAX_INT:2147483647;小于负整数能表示的范围时返回MIN_INT:-2147483648。

我们先设置一些变量:

  • sign用来处理数字的正负,当为正时sign > 0,当为负时sign < 0
  • n存放最终转换后的结果
  • c表示当前数字

而后,你可能会编写如下代码段处理溢出问题:

//当发生正溢出时,返回INT_MAX
if ((sign == '+') && (c > MAX_INT - n * 10))
{ n = MAX_INT;
break;
}
//发生负溢出时,返回INT_MIN
else if ((sign == '-') && (c - 1 > MAX_INT - n * 10))
{
n = MIN_INT;
break;
}

但当上述代码转换" 10522545459"会出错,因为正常的话理应得到MAX_INT:2147483647,但程序运行结果将会是:1932610867。

为什么呢?因为当给定字符串" 10522545459"时,而MAX_INT是2147483647,即MAX_INT(2147483647) < n*10(1052254545*10),所以当扫描到最后一个字符‘9’的时候,执行上面的这行代码:

c > MAX_INT - n * 10

已无意义,因为此时(MAX_INT - n * 10)已经小于0,程序已经出错。

针对这种由于输入了一个很大的数字转换之后会超过能够表示的最大的整数而导致的溢出情况,我们有两种处理方式可以选择:

  • 一个取巧的方式是把转换后返回的值n定义成long long,即long long n;
  • 另外一种则是只比较n和MAX_INT / 10的大小,即:
    • 若n > MAX_INT / 10,那么说明最后一步转换时,n*10必定大于MAX_INT,所以在得知n > MAX_INT / 10时,当即返回MAX_INT。
    • 若n == MAX_INT / 10时,那么比较最后一个数字c跟MAX_INT % 10的大小,即如果n == MAX_INT / 10且c > MAX_INT % 10,则照样返回MAX_INT。

对于上面第一种方式,虽然我们把n定义了长整型,但最后返回时系统会自动转换成整型。咱们下面主要来看第二种处理方式。

对于上面第二种方式,先举两个例子说明下:

  • 如果我们要转换的字符串是"2147483697",那么当我扫描到字符'9'时,判断出214748369 > MAX_INT / 10 = 2147483647 / 10 = 214748364(C语言里,整数相除自动取整,不留小数),则返回MAX_INT;
  • 如果我们要转换的字符串是"2147483648",那么判断最后一个字符'8'所代表的数字8与MAX_INT % 10 = 7的大小,前者大,依然返回MAX_INT。

一直以来,我们努力的目的归根结底是为了更好的处理溢出,但上述第二种处理方式考虑到直接计算n *10 + c 可能会大于MAX_INT导致溢出,那么便两边同时除以10,只比较n和MAX_INT / 10的大小,从而巧妙的规避了计算n*10这一乘法步骤,转换成计算除法MAX_INT/10代替,不能不说此法颇妙。

如此我们可以写出正确的处理溢出的代码:

c = *str - '0';
if (sign > 0 && (n > MAX_INT / 10 || (n == MAX_INT / 10 && c > MAX_INT % 10)))
{
n = MAX_INT;
break;
}
else if (sign < 0 && (n > (unsigned)MIN_INT / 10 || (n == (unsigned)MIN_INT / 10 && c > (unsigned)MIN_INT % 10)))
{
n = MIN_INT;
break;
}

从而,字符串转换成整数,完整的参考代码为:

int StrToInt(const char* str)
{
static const int MAX_INT = (int)((unsigned)~0 >> 1);
static const int MIN_INT = -(int)((unsigned)~0 >> 1) - 1;
unsigned int n = 0; //判断是否输入为空
if (str == 0)
{
return 0;
} //处理空格
while (isspace(*str))
++str; //处理正负
int sign = 1;
if (*str == '+' || *str == '-')
{
if (*str == '-')
sign = -1;
++str;
} //确定是数字后才执行循环
while (isdigit(*str))
{
//处理溢出
int c = *str - '0';
if (sign > 0 && (n > MAX_INT / 10 || (n == MAX_INT / 10 && c > MAX_INT % 10)))
{
n = MAX_INT;
break;
}
else if (sign < 0 && (n >(unsigned)MIN_INT / 10 || (n == (unsigned)MIN_INT / 10 && c > (unsigned)MIN_INT % 10)))
{
n = MIN_INT;
break;
} //把之前得到的数字乘以10,再加上当前字符表示的数字。
n = n * 10 + c;
++str;
}
return sign > 0 ? n : -n;
}

举一反三

  1. 实现string到double的转换

分析:此题虽然类似于atoi函数,但毕竟double为64位,而且支持小数,因而边界条件更加严格,写代码时需要更加注意。

如何实现字符串转换成整数(实现atoi内置函数)?的更多相关文章

  1. 算法练习-字符串转换成整数(实现atoi函数)

    练习问题来源 https://leetcode.com/problems/string-to-integer-atoi/ https://wizardforcel.gitbooks.io/the-ar ...

  2. 面试题49:把字符串转换成整数(atoi)

    需要考虑的问题都已在程序中注释 bool isValid; int StrToInt(const char* str) { isValid = false; //不合法情形1:空指针 if (str ...

  3. [Leetcode] String to integer atoi 字符串转换成整数

    Implement atoi to convert a string to an integer. Hint: Carefully consider all possible input cases. ...

  4. 17.把字符串转换成整数[atoi]

    [题目] 把字符串转换成整数,需要考虑字符串有效性. [代码]  C++ Code  123456789101112131415161718192021222324252627282930313233 ...

  5. 【Java】 剑指offer(67) 把字符串转换成整数

      本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 请你写一个函数StrToInt,实现把字符串转换成整数这个功能 ...

  6. 《剑指offer》第六十七题(把字符串转换成整数)

    // 面试题67:把字符串转换成整数 // 题目:请你写一个函数StrToInt,实现把字符串转换成整数这个功能.当然,不 // 能使用atoi或者其他类似的库函数. #include <ios ...

  7. 剑指offer——把字符串转换成整数(c++)

    题目描述请你写一个函数StrToInt,实现把字符串转换成整数这个功能.当然,不能使用atoi或者其他类似的库函数. 示例 1:输入: " -42"输出: -42解释: 第一个非空 ...

  8. 【剑指Offer学习】【面试题49:把字符串转换成整数】

    题目:实现一个函数stringToInt,实现把字符串转换成整数这个功能.不能使用atoi或者其它相似的库函数. 题目解析 这看起来是非常easy的题目,实现基本功能 ,大部分人都能用10行之内的代码 ...

  9. [LeetCode]面试题67. 把字符串转换成整数

    题目 写一个函数 StrToInt,实现把字符串转换成整数这个功能.不能使用 atoi 或者其他类似的库函数. 首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止. 当我们 ...

随机推荐

  1. Python实现性能自动化测试竟然如此简单【颠覆你的三观】

    一.思考 1.什么是性能自动化测试?   性能系统负载能力 超负荷运行下的稳定性 系统瓶颈 自动化测试使用程序代替手工 提升测试效率 性能自动化使用代码模拟大批量用户 让用户并发请求 多页面多用户并发 ...

  2. selenium自动化测试实战——12306铁路官网范例

    一.Selenium介绍 Selenium 是什么?一句话,自动化测试工具.它支持各种浏览器,包括 Chrome,Safari,Firefox 等主流界面式浏览器,如果你在这些浏览器里面安装一个 Se ...

  3. jupyter中%matplotlib inline报错

    学习matplotlib时,使用的jupyter跑代码.报错如上图.大致就是后面的注释不能被识别.我寻思着注释不用识别吧,大概是因为%后跟的语句被全部当成命令行执行了,然后命令行不识别行内注释,导致报 ...

  4. p40_数据交换方式

    一.为什么要数据交换 数据链路发展史: 二.数据交换方式 电路交换 报文交换 分组交换[数据报方式,虚电路方式] 三.电路交换 eg:电话网络(特点:**独占资源,**即使两个人不说话,链接也不会被别 ...

  5. HDU - 1520 Anniversary party (树的最大独立集)

    Time limit :1000 ms :Memory limit :32768 kB: OS :Windows There is going to be a party to celebrate t ...

  6. STL源码剖析:仿函数

    仿函数就是函数对象 函数对象: 重载了operator()的类对象 使用起来和普通函数一致,所以称为函数对象或是仿函数 STL中对于仿函数的参数进行了特殊处理,定义了两个特殊类,类里面只有类型定义 一 ...

  7. Residual Attention Network for Image Classification(CVPR 2017)详解

    一.Residual Attention Network 简介 这是CVPR2017的一篇paper,是商汤.清华.香港中文和北邮合作的文章.它在图像分类问题上,首次成功将极深卷积神经网络与人类视觉注 ...

  8. Kubernetes中强制删除Pod、namespace

    Kubernetes中强制删除Pod.namespace 解决方法 可使用kubectl中的强制删除命令 # 删除POD kubectl delete pod PODNAME --force --gr ...

  9. Java-旋转字符串

    描述 旋转字符串 给定一个字符串(以字符数组的形式给出)和一个偏移量,根据偏移量原地旋转字符串(从左向右旋转). 挑战 在数组上原地旋转,使用O(1)的额外空间 说明 原地旋转意味着你要在s本身进行修 ...

  10. 手写Vuex源码

    Vuex原理解析 Vuex是基于Vue的响应式原理基础,所以无法拿出来单独使用,必须在Vue的基础之上使用. 1.Vuex使用相关解析 main.js   import store form './s ...