字符串转整数一一atoi

C 语言中整数与字符串的相互转换是在平常用着比较多的。我们都知道用atoi函数能将字符串转换成整数。atoi看起来很容易写,但是你真的考虑过具体细节、是否符合要求呢?

atoi简易版本,不考虑细节问题

int my_atoi(const char *str)
{
    if(NULL == str)
        return 0;
    int ret = 0;
    while(0 != *str)
    {
        ret = ret * 10 + *str - '0';
        str++;
    }
    return ret;
}

从函数来看,就是遍历字符串,每遇到一个数字就加上原来的值乘以10。程序看去,没有什么毛病,例如:“1234”,都能正确的输出。但是如果要处理下面这种情况呢?

"-1234"
"+1234"
"  "
"12345678910"
""
"123aab"

可以试一下,会发现并不是想象中的那样?

atoi考虑细节版本

int String_atoi(char *str)
{
    char flag = '+';//指示结果是否带符号 
    long res = 0;
    
    while (' ' == (*str)) //跳过开始的空格
    	str++;

    if(*str=='-')//字符串带负号 
    {
        str++;
        flag = '-';//将标志设为负号 
    }
    if(*str=='+')//字符串带正号 
    {
        str++;//指向下一个字符 
        flag = '+';//将标志设为正号 
    } 

    //逐个字符转换,并累加到结果res 
    while(*str >= 48 && *str < 57)//如果是数字才进行转换,数字0~9的ASCII码:48~57 
    {
        res = 10 * res + *str - 48;//字符'0'的ASCII码为48
        str++;
    } 
 
    if(flag == '-')//处理是负数的情况
    {
        res = -res;
    }

    if(flag == '+')//处理是正数的情况
    {
        res = +res;
    }
 
    return (int)res;
}

看上面的代码你看你注意到了,实现atoi需要考虑这些方面:

1.输入正负号
2.开头有空格
3.空字符串
...

咱再看看函数源码是怎么考虑细节问题的

int  atoi(const char *nptr)
{
        return (int)atol(nptr);
}
 
long  atol(const char *nptr)
{
        int c;              /* 当前要转换的字符(一个一个字符转换成数字) */
        long total;         /* 当前转换结果 */
        int sign;           /* 标志转换结果是否带负号*/
 
        /*跳过空格,空格不进行转换*/
        while ( isspace((int)(unsigned char)*nptr) )
            ++nptr;
 
        c = (int)(unsigned char)*nptr++;//获取一个字符准备转换 
        sign = c;           /*保存符号标示*/
        if (c == '-' || c == '+')
            c = (int)(unsigned char)*nptr++;    /*跳过'+'、'-'号,不进行转换*/
 
        total = 0;//设置转换结果为0 
 
        while (isdigit(c)) {//如果字符是数字 
            total = 10 * total + (c - '0');     /* 根据ASCII码将字符转换为对应的数字,并且乘10累积到结果 */
            c = (int)(unsigned char)*nptr++;    /* 取下一个字符 */
        }
 
         //根据符号指示返回是否带负号的结果 
        if (sign == '-')
            return -total;
        else
            return total;  
}

现在来做一下对比,验证是否真的是上面说的那样:

#include <stdio.h>
#include <stdlib.h> //atoi

int String_atoi(char *str);//函数声明 
int my_atoi(const char *str);

int main(int argc, char const *argv[])
{
	printf("\"String_atoi\"字符串转换为数字:%d\n",String_atoi("1234"));
    printf("\"String_atoi\"字符串转换为数字:%d\n",String_atoi("-1234"));
    printf("\"String_atoi\"字符串转换为数字:%d\n",String_atoi("+1234"));
    printf("\"String_atoi\"字符串转换为数字:%d\n",String_atoi("  "));
    printf("\"String_atoi\"字符串转换为数字:%d\n",String_atoi("12345678910"));
    printf("\"String_atoi\"字符串转换为数字:%d\n",String_atoi(""));
    printf("\"String_atoi\"字符串转换为数字:%d\n",String_atoi("123aab"));

    printf("================================\n");
    printf("\"atoi\"字符串转换为数字:%d\n",atoi("1234"));
    printf("\"atoi\"字符串转换为数字:%d\n",atoi("-1234"));
    printf("\"atoi\"字符串转换为数字:%d\n",atoi("+1234"));
    printf("\"atoi\"字符串转换为数字:%d\n",atoi("  "));
    printf("\"atoi\"字符串转换为数字:%d\n",atoi("12345678910"));
    printf("\"atoi\"字符串转换为数字:%d\n",atoi(""));
    printf("\"atoi\"字符串转换为数字:%d\n",atoi("123aab"));

    printf("================================\n");
    printf("\"my_atoi\"字符串转换为数字:%d\n",my_atoi("1234"));
    printf("\"my_atoi\"字符串转换为数字:%d\n",my_atoi("-1234"));
    printf("\"my_atoi\"字符串转换为数字:%d\n",my_atoi("+1234"));
    printf("\"my_atoi\"字符串转换为数字:%d\n",my_atoi("  "));
    printf("\"my_atoi\"字符串转换为数字:%d\n",my_atoi("12345678910"));
    printf("\"my_atoi\"字符串转换为数字:%d\n",my_atoi(""));
    printf("\"my_atoi\"字符串转换为数字:%d\n",my_atoi("123aab"));


    return 0;
}
 
int String_atoi(char *str)
{
    char flag = '+';//指示结果是否带符号 
    long res = 0;
    
    while (' ' == (*str)) //跳过开始的空格
    	str++;

    if(*str=='-')//字符串带负号 
    {
        str++;
        flag = '-';//将标志设为负号 
    }
    if(*str=='+')//字符串带正号 
    {
        str++;//指向下一个字符 
        flag = '+';//将标志设为正号 
    } 

    //逐个字符转换,并累加到结果res 
    while(*str >= 48 && *str < 57)//如果是数字才进行转换,数字0~9的ASCII码:48~57 
    {
        res = 10 * res + *str - 48;//字符'0'的ASCII码为48
        str++;
    } 
 
    if(flag == '-')//处理是负数的情况
    {
        res = -res;
    }

    if(flag == '+')//处理是正数的情况
    {
        res = +res;
    }
 
    return (int)res;
}

int my_atoi(const char *str)
{
    if(NULL == str)
        return 0;
    int ret = 0;
    while(0 != *str)
    {
        ret = ret * 10 + *str - '0';
        str++;
    }
    return ret;
}

输出结果:
在这里插入图片描述

上面三个函数进行对比,代码中设置的需要根据需求而定,例如如果认为空字符串或只有负号转换是非法的,那么前面的代码将不符合要求,再重新实现。但这些都不是重点,重点是我们在考虑实现atoi函数的时候,需要考虑多种异常场景。

在这里插入图片描述

扫二维码关注微信公众号,获取技术干货

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值