atoi的一个实现

1 篇文章 0 订阅

leetcode 上有一道实现 atoi 题目。两年前我参加百度校招面试就被问到过这个题目。解决一个问题的方法很多,最简单的方法自然是用一个现成的方法解决之。譬如:

c++ 简单版本:


   
   
  1. #include <sstream>
  2. class Solution {
  3. public:
  4. int myAtoi(string s) {
  5. int v {0};
  6. std::istringstream stream {s};
  7. stream >> v;
  8. return v;
  9. }
  10. };

c 简单版本:


   
   
  1. #include <stdlib.h>
  2. #include <limits.h>
  3.  
  4. int myAtoi(char* s) {
  5. long long v = atoll(s);
  6. return v > INT_MAX ? INT_MAX : v < INT_MIN ? INT_MIN : v;
  7. }

c++ 版本对应的 c 版本: sscanf(str, "%d", &v) 是无效的,因为 c 没有规定溢出下的情况,而 c++ 有。恰好, c++ 溢出时的处理和本道题目一致,故方法真的很简单。

如果要重新发明 atoi 的轮子(面试的时候就是酱紫!),而不是用轮子替代轮子,下面是一个参考实现:


   
   
  1. #include <limits.h>
  2.  
  3. #define is_digit(a) ((a) >= '0' && (a) <= '9')
  4. #define is_space(a) ((a) == ' ' || (a) == '\t')
  5.  
  6. int myAtoi(char* s) {
  7. if(!s || !*s) return 0;
  8. while(is_space(*s)) ++s;
  9. int sign = *s != '-';
  10. if(*s == '+' || *s == '-') ++s;
  11. if(!is_digit(*s)) return 0;
  12. unsigned v = *s - '0', upper = sign > 0 ? INT_MAX : INT_MIN;;
  13. while(*++s && is_digit(*s)){
  14. if(v > upper/10 || (v = v * 10 + (*s-'0')) > upper){
  15. return sign ? INT_MAX : INT_MIN;
  16. }
  17. }
  18. return sign ? v : -v;
  19. }

最核心部分不是计算,而是溢出的判断。溢出的判断有多种方法:

  • 使用 long long 判断是否溢出:一般来说 sizeof(int) < sizeof(long long),这样的话,试用 long long 直接保存 int * 10 + int 的结果没有问题,然后和 INT_MAX、INT_MIN 对比;
  • 将 *10 操作转化为加法操作,然后使用符号改变来判断溢出;
  • 比较 v 和 MAX/10、-INT/10 的大小,判断溢出(这里采用的方法)。

不采用第一种方法不是因为其不好,而是某些地方不够通用,譬如我们求 atoll,这样哪来的更长的 int 呢?第二种方法比较通用,就是需要多次计算加法。 第三种简单些,也通用些,但有些基本假定,譬如 sizeof(int) 长度不能太短,需要保证 UINT_MAX - INT_MAX > 9 !那么 int 至少得 5 位,几乎所有系统都满足的吧!

注:补充几句。补码表示的整数在正负取值上并不对称,譬如 32 位整数的 INT_MAX = 2147483647,INT_MIN = -2147483648,UINT_MAX = 4294967295 。

作者:文琼


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值