字符串转换为整数,相关问题探讨

问题:输入一串数字字符串,经过转换输出为整数,例如“12345”,转换为12345。

分析如下:
1.确定扫描方向,从左至右
2.具体转换:a. 1 = 0*10+1,b. 12=1*10+2,…..如此循环

int str2int(const char* str)
{
    int temp = 0;
    while(*str != '\0')
    {
        temp = temp*10+(*str-'0');
        ++str;
    }
    return temp;
}

以上代码过于简陋,很多问题没有考虑到:
1.要确认字符串是否为空,assert(str != NULL)。
2.数字字符串正负问题,“-12345”和“12345”之间的区别。
3.要确认字符串是否为正确的数字字符串。
4.数字字符串过长,产生溢出的问题,又该如何处理。(重点)

下面逐个进行讨论:
1.是否为空,这个比较简单,上面已经说明,或者如下:

if (str == NULL)
{
    printf("str error!\n");
    return 0;
}

2.正负问题:

int signFlag = 1;
if (*str == '+')
{
    signFlag = 1;
    str++;
}
else if (*str == '-')
{
    signFlag = -1;
    str++;
}

3.是否为完整数字字符串:

if (*str < '0' || *str > '9')
{
    printf("str Error!\n");
    break;
}

4.溢出处理:
根据数据类型的大小,当输入的数字字符串转换为整数的值,超出了合理范围的上限,输出上限值,超出了合理范围下限,输出下限值。

以下为各数据类型大小的介绍:(来源网络)
变量的长度(VC6环境下)

char      8 (bit)
short     16
int       32  通常同具体的机器长度相同
long      32
float     32
double    64

变量的范围(VC6环境下)

signed char             -128~127
unsigned char           0~255
signed short            -32768~32767
unsigned short          0~0xffff
signed int              (-2147483647 - 1)~2147483647
unsigned int            0~0xffffffff
signed long             (-2147483647L - 1)~2147483647
unsigned long           0~0xffffffffUL
float                   1.175494351e-38F/* min pos value */   
                        3.402823466e+38F  /* max value */ 
double                  3.3621031431120935063e-4932L   
                        1.189731495357231765e+4932L

我们以这个为例子:signed int (-2147483647 - 1)~2147483647

const int Max_int = (int)((unsigned int)~0>>1);
const int Min_int = -(int)((unsigned int)~0>>1)-1;

那么问题来了,我们该怎样去判断该数字字符串转换的整数是属于(-2147483647 - 1)~2147483647这个区间的呢?
那我们可以列出几个例子做出比较,“2147483647999”和2147483647,“2147483648“和2147483647,等等。这样的比较依旧无法进行,因为数据会溢出,溢出了就会存在错误的比较。
我们可以考虑降级比较,即把数据字符串和2147483647/10进行比较,就拿“2147483648“和2147483647进行分析。
1.当数据字符串为“214748364”时(即扫描到2147483648倒数第二位),214748364”和2147483647/10相等。
2.当数字字符串“2147483648“扫描到最后一位‘8’时,和2147483647%10的7就不相等。
根据这样的分析就可以得到以下实现代码:

if (signFlag == 1 && (n>Max_int/10 || (n==Max_int/10 && c>Max_int%10)))
{
    n = Max_int;
    break;
}
else if (signFlag == -1 && (n>(unsigned)Min_int/10 || (n == (unsigned)Min_int/10 && c>(unsigned)Min_int%10)))
{
    n = Min_int;
    break;
}

具体实现代码:

#include <iostream>
using namespace std;

const int Max_int = (int)((unsigned int)~0>>1);
const int Min_int = -(int)((unsigned int)~0>>1)-1;

int str2int(char* str)
{
    //字符串判断
    if (str == NULL)
    {
        printf("str error!\n");
        return 0;
    }

    //符号处理
    int signFlag = 1;
    if (*str == '+')
    {
        signFlag = 1;
        str++;
    }
    else if (*str == '-')
    {
        signFlag = -1;
        str++;
    }

    int n = 0;
    while (*str != '\0')//字符串遍历
    {
        if (*str < '0' || *str > '9')//数字字符串判断
        {
            printf("str Error!\n");
            break;
        }

        //溢出处理
        int c = *str - '0';
        if (signFlag == 1 && (n>Max_int/10 || (n==Max_int/10 && c>Max_int%10)))
        {
            n = Max_int;
            break;
        }
        else if (signFlag == -1 && (n>(unsigned)Min_int/10 || (n == (unsigned)Min_int/10 && c>(unsigned)Min_int%10)))
        {
            n = Min_int;
            break;
        }

        //转换处理
        n = n*10 + (*str - '0');
        ++str;
    }

    return signFlag>0?n:-n;
}

int main()
{
    char *strdata0 = "-123456789987654321";
    char *strdata1 = "123456789987654321";
    char *strdata2 = "-12345678";
    char *strdata3 = "12345678";
    char *strdata4 = "1234k678";
    int temp =str2int(strdata0);
    printf("\"-123456789987654321\"输出为:%d\n",temp);
    temp =str2int(strdata1);
    printf("\"123456789987654321\"输出为:%d\n",temp);
    temp =str2int(strdata2);
    printf("\"-12345678\"输出为:%d\n",temp);
    temp =str2int(strdata3);
    printf("\"12345678\"输出为:%d\n",temp);
    temp =str2int(strdata4);
    printf("\"1234k678\"输出为:%d\n",temp);
    system("pause");
    return 0;
}

这里写图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值