字符串转换成整数

2023-10-27

题目描述

输入一个由数字组成的字符串,把它转换成整数并输出。例如:输入字符串"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位,而且支持小数,因而边界条件更加严格,写代码时需要更加注意。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

字符串转换成整数 的相关文章

  • SVC分类经典Iris数据集

    今天做了一个用SVC分类经典Iris数据集的训练 在数据预处理上出了点奇怪的岔子 对原始数据中的string转到float这步一直不成功 转换函数没错 用的是load txt里面的converters 一直报错 但是被我机智 愚蠢 地手动处
  • Tomcat安装部署及多实例部署介绍

    Tomcat 一 Tomcat相关简介 二 Tomcat安装 三 多实例 一 Tomcat相关简介 1 Tomcat简介 Tomcat是由Apache软件基金会下属的Jakarta项目开发的一个servelet容器 按照Sun micros
  • word如何首页和目录不编辑页码

    按照下面的方法 从第二页或者是需要的地方设置页码即可 页码从任意页开始 1 将光标定位于需要开始编页码的页首位置 2 选择 插入 分隔符 打开 分隔符 对话框 在 分隔符类型 下单击选中 下一页 单选钮 3 选择 视图 页眉和页脚 并将光标
  • 作为程序员,该如何提升自己的编程水平?

    1500字3个角度说明如何提升编程水平 一 如果你是初学者 这几个方法给你 1 1 刻意练习 在编写代码之前 首先我们可以先了解这门编程语言的基本用法和常用的概念 编写基本的程序 一般来说敲代码是步骤是 明确需求 设计程序 编写代码 完善程
  • #35. 二叉树遍历(flist)(4月3日)

    include
  • Java基础篇:如何使用 break 退出循环

    在 Java 中 break 语句有 3 种作用 第一 你已经看到 在 switch 语句中 它被用来终止 一个语句序列 第二 它能被用来退出一个循环 第三 它能作为一种 先进 的goto 语句来使用 下面对最后 2 种用法进行解释 使用
  • 【Java】利用 PDF 多页模板生成 PDF 并导出

    一 所需要的依赖
  • 数据中心托管有什么好处?

    1 内置可扩展性 除了能够节省建设一个新的数据中心的资金 当涉及到可扩展的计算资源时 得益于数据中心托管服务的固有灵活性 还可以让用户节省更多的成本费用 托管服务提供商能够根据用户需求扩展或减少他们所需要的容量 这样 既有效利用了资源 还能
  • 使用eclipse创建一个图书管理系统(2)---------逻辑的实现

    就像使用C语言写代码一样 比如要用 C语言写一个小游戏的代码 我们的逻辑实现是在哪里实现的啊 是不是在一个test c源文件里面啊 没错 就是的 在之前的文章里 我说过我定义的Main函数就像C语言里的test c文件一样 所以 为了不打自
  • web安全之文件上传漏洞攻击与防范方法

    一 文件上传漏洞与WebShell的关系 文件上传漏洞是指网络攻击者上传了一个可执行的文件到服务器并执行 这里上传的文件可以是木马 病毒 恶意脚本或者WebShell等 这种攻击方式是最为直接和有效的 部分文件上传漏洞的利用技术门槛非常的低
  • HTTP 协议

    1 HTTP 介绍 2 HTTP 请求 和 响应 3 HTTP 请求方法 4 HTTP 状态码 5 HTTP 头信息 6 URL 和 URI 7 静态资源 和 动态资源 1 HTTP 介绍 HTTP协议 是 超文本传输协议 的缩写 是用于从
  • “该应用程序的数字签名无法验证......”

    该应用程序的数字签名无法验证 是否运行该应用程序 登录服务器后运行某模块时 总出现这个提示 且对话框点不动 解决 开始 控制面板 双击JAVA 打开JAVA面板 高级 安全 混合代码 沙箱代码与可信代码 安全验证 禁用验证 不推荐 图片见附
  • 【k8s故障处理篇】解决k8s集群中kubectl命令补全问题

    k8s故障处理篇 解决k8s集群中kubectl命令补全问题 一 查看k8s的版本 二 安装相关软件包 三 配置相关环境变量 四 测试tab键补齐命令 一 查看k8s的版本 查看当前k8s版本 当前环境的k8s版本为v1 16 2 本方法也
  • 解决网页不能粘贴的问题

    最近要完成老师布置的英语作业 在网站上写作文并提交 但是老师设置了 不能复制粘贴 本来在word文档里写完打好草稿了 现在却只能重新打一遍 于是我尝试解决这个问题 看看能不能粘贴上去 通过查阅资料 了解了网页的基本知识 于是探索出了如下步骤
  • 在React项目中实现调用摄像头拍照的功能

    文章目录 前言 一 如何调用摄像头 二 操作步骤 1 准备dom元素 2 添加打开和关闭摄像头的事件 3 获取图片 base64格式 三 demo 总结 前言 在日常开发中可能会遇到需要调用摄像头拍照的功能 下面为大家讲解一下在react项
  • Qt如何设置界面透明

    1 设置主窗体透明 但是窗体上的控件不透明 setAttribute Qt WA TranslucentBackground true void paintEvent QPaintEvent event QPainter painter t
  • Go入门:切片 slice,引用类型

    Go 语言中 slice表示一个拥有相同类型元素的可变长度序列 slice通常被写为 T 其中元素的类型都是T 它看上去就像没有长度的数组类型 数组和slice其实是紧密关联的 var fslice int 和声明array一样 只是少了长
  • mac版Idea快捷键

    option command L 格式化 option command M 提取方法 option command T 代码块加try catch fn shift f6 修改变量 方法名 shift command 折叠代码 shift
  • 从Java到Go:使用Go语言和Gin Web框架构建博客系统

    目录 1 Go语言基本介绍 2 从Java到Go 语法和特性对比 2 1 变量和类型 2 2 控制结构

随机推荐

  • js什么是事件冒泡并阻止事件冒泡

    事件冒泡 当事件发生后 这个事件就要开始传播 从里到外或者从外向里 为什么要传播呢 因为事件源本身 可能 并没有处理事件的能力 即处理事件的函数 方法 并未绑定在该事件源上 例如我们点击一个按钮时 就会产生一个click事件 但这个按钮本身
  • 【满分】【华为OD机试真题2023 JS】预定酒店

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 预定酒店 知识点排序 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 放暑假了 小明决定到某旅游景点游玩 他在网上搜索到了各种价位的酒店 长度为n的数组A 他的心
  • 区块链的证明机制(Proof Of Work POW)学习心得(参考luotuo视频学习)

    在区块链学习中 参考luotuo的哔哩哔哩视频 区块链增加模块时是要经过计算的 只有计算到 开头n位为0 符合这个链条的规则时 才会将这个新的区块加入到区块链当中 这个计算hash的方法应该被加以判断 也就是增加一个方法来计算符合区块链难度
  • CSDN博客如何设置的更美观和贴好看的代码

    之前学习写博客时想要写出整洁的博文 贴好看的代码 所以百度了好多位小可爱的方法 奈何我太笨可能对我帮助不是很大 依然是一头雾水 我是想要找到那种黑色背景代码高亮的方式 后来自己慢慢琢磨出来了 所以把我的方法分享一下 1 在博客设置首页有博客
  • hive on spark 3.1.2集成spark3.0.0

    需要修改spark env sh 加上 export SPARK DIST CLASSPATH hadoop classpath 否则报错 2 14 51 56 117 INFO yarn ApplicationMaster Final a
  • 盘点2022年有影响力的五种顶级NFT头像

    盘点2022年15 个顶级NFT头像 NFT头像在去年风靡一时 作为一种简单的即插即用方法 任何人都可以将特征 身体 头部 背景等 加载到应用程序中以快速混合搭配 NFT 创建 因此它已成为制作头像比以往任何时候都容易 考虑到今年 NFT热
  • 美团外卖与饿了么竞品分析

    截至2020年3月 我国网上外卖用户规模达3 98亿 占网民整体的44 手机网上外卖用户规模达3 97亿 占手机网民整体的44 2 图片来源 前瞻网 2017 2019年 我国互联网餐饮外卖交易规模逐渐扩大 2019全年超7274亿元 互联
  • Web自动化测试面试

    一 Web 自动化测试 1 Selenium 中 hidden 或者是 display none 的元素是否可以定位到 不能 可以写 JavaScript 将标签中的 hidden 先改为 0 再定位元素 2 Selenium 中如何保证操
  • 安卓APP_ 布局(4) —— TableLayout表格布局

    摘自 安卓APP 布局 4 TableLayout表格布局 作者 丶PURSUING 发布时间 2021 04 11 22 55 50 网址 https blog csdn net weixin 44742824 article detai
  • 集合竞价

    include
  • Linux 创建目录和文件

    mkdir 创建目录 在linux中 mkdir是创建目录的意思 是 make directories 的缩写 该命令用于创建新的目录 语法为 mkdir mp 目录名 设置参数 m 用于手动配置创建目录的权限 设置参数 p 用于递归创建所
  • 苹果Vision Pro手势+眼球融合交互的奥秘

    毫无疑问 Vision Pro在眼球追踪 手势的融合交互体验上 给AR VR头戴设备带来了新突破 在用户体验上的提升非常明显 那么 为什么Vision Pro上这一功能会被如此值得关注呢 为了弄清楚 我们先来看看主流VR设备是如何做的 主流
  • Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding

    Fatal Python error init fs encoding failed to get the Python codec of the filesystem encoding Python runtime state core
  • 循迹小车代码应该怎么写?

    循迹小车的代码通常包括以下几个部分 引入库和定义变量 首先需要引入所需的库 并定义各个引脚对应的变量 以便后面的代码可以直接使用 初始化设置 对循迹小车进行初始化设置 如设置电机转向 速度等参数 读取循迹传感器数值 通过循迹传感器读取黑线和
  • 用jQuery编写简单的动画效果

    jQuery是一种基于JavaScript库的快速 小型而且特别丰富的JavaScript库 它极大地简化了HTML文档遍历和操作 事件处理 动画效果和AJAX交互等功能 jQuery中的各种动画函数可以让我们轻松地为网页添加各种各样的动画
  • Leetcode 刷题笔记:字符串篇

    结束了忙碌的期末 终于有了一个月的冬假 赶紧利用这段时间集中精力把Leetcode刷起来 1 Leetcode344 反转字符串 题解 难度 这道题目算是比较基础也是很简单的一道题目了 用双指针的方法可以轻松解决 时间复杂度O N 空间复杂
  • ES集成IK分词器

    一 下载IK分词器 注意版本与ES版本保持一致 下载地址 https github com medcl elasticsearch analysis ik releases 二 下载之后解压到ES的plugin目录 注意新建一个ik目录 解
  • 运行jar包时指定jdk的版本

    set JAVA HOME C Program Files Java jdk1 8 0 153 set CLASSPATH JAVA HOME lib dt jar JAVA HOMe lib tools jar set Path JAVA
  • CryptoPP版本验证

    在使用第三方程序库时 可能会遇到程序库的版本不匹配的问题 下面介绍在使用CryptoPP时 如何验证其版本 代码如下 include
  • 字符串转换成整数

    题目描述 输入一个由数字组成的字符串 把它转换成整数并输出 例如 输入字符串 123 输出整数123 给定函数原型int StrToInt const char str 实现字符串转换成整数的功能 不能使用库函数atoi 分析与解法 本题考