C中数字字符串转double和int实现原理

C中,数字字符串以char[]形式定义。

相关api见《c++中数字与string转换》

 

① 常用函数

 

#include<stdlib.h>

atoi  --- 转int

atod  --- 转double

strtod --- 转double

strtol  --- 转long

 

四兄弟的工作原理都可以用相似的语言描述:

函数会扫描参数 nptr字符串,跳过前面的空白字符等,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时('\0')结束转换。

去空白,留正负,存数字。

 

四兄弟中,strtod和strtol双胞胎的特殊之处在于:

它们的参数含2个指针,第二个指针返回扫描结束的位置的指针

int atoi(const char *nptr);
double atof(const char *nptr);

long int strtol(const char *nptr,char **endptr,int base);
double strtod(const char *nptr,char **endptr);

 

②实现原理

2.1 atoi

int Atoi(const char *pstr)
{
    int sign = 1;
    int num = 0;

    while (*pstr == ' ' || *pstr == '\t') //原文是'/t'有误
    {
        pstr++;
    }

    if (*pstr == '-')
    {
        sign = -1;
        pstr++;
    }

    while (*pstr)
    {
        if (*pstr >= '0' && *pstr <= '9')
        {
            num = 10 * num + *pstr - '0';
        }
        else
        {
            return num * sign;
        }
        pstr++;
    }
    return (num * sign);
}

 

2.2 atof

 

double Atof(const char *pstr)
{
    double sign = 1.0;
    double num1 = 0.0;
    double num2 = 0.0;
    double point = 0.1;

    while (*pstr == ' ' || *pstr == '/t')
    {
        pstr++;
    }

    if (*pstr == '-')
    {
        sign = -1;
        pstr++;
    }

    while (*pstr)
    {
        if (*pstr == '.')
        {
            pstr++;
            while (*pstr >= '0' && *pstr <= '9')
            {
                num1 += point * (*pstr - '0');
                point *= 0.1;
                pstr++;
            }
        }
        else if (*pstr >= '0' && *pstr <= '9')
        {
            num2 = num2 * 10 + *pstr -'0';
        }
        else
        {
            return (num1 + num2) * (sign);
        }
        pstr++;
    }
    return (num1 + num2) * (sign);
}

 

2.3 strtol

#define TOLOWER(x) ((x) | 0x20)  
#define isxdigit(c)    (('0' <= (c) && (c) <= '9') /  
             || ('a' <= (c) && (c) <= 'f') /  
             || ('A' <= (c) && (c) <= 'F'))  
  
#define isdigit(c)    ('0' <= (c) && (c) <= '9')  
  
unsigned long strtoul(const char *cp,char **endp,unsigned int base)  
{  
    unsigned long result = 0,value;  
  
    if (!base) {  
        base = 10;  
        if (*cp == '0') {  
            base = 8;  
            cp++;  
            if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {  
                cp++;  
                base = 16;  
            }  
        }  
    } else if (base == 16) {  
        if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')  
            cp += 2;  
    }  
    while (isxdigit(*cp) &&  
           (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {  
        result = result*base + value;  
        cp++;  
    }  
    if (endp)  
        *endp = (char *)cp;  
    return result;  
}  
long strtol(const char *cp,char **endp,unsigned int base)  
{  
    if(*cp=='-')  
        return -strtoul(cp+1,endp,base);  
    return strtoul(cp,endp,base);  
}  

 

2.4 strtod

 

double Strtod(char *str, char **endstr){
    double num1 = 0.0;
    double num2 = 0.0;
    double point = 0.1;
    int sign = 1;

    int len = strlen(str) + 1;
    *endstr = new char[len];
    memset(*endstr, 0, len);

    if (*str == '-')
    {
        sign = -1;
        ++str;
    }

    if (!isdigit(*str))
    {
        strcpy(*endstr, str);
        return 0.0;
    }
    while (*str && isdigit(*str))
    {
        if (*str == '.')
        {
            ++str;
            while (*str && isdigit(*str))
            {
                num2 += point * ((*str) - '0');
                point *= 0.1;
                ++str;
            }
            strcpy(*endstr, str);
            break;
        }
        else
        {
            num1 = 10 * num1 + *str - '0';
            str++;
            if (!*str || !isdigit(*str))
            {
                strcpy(*endstr, str);
                break;
            }
        }
    }
    
    return (num1 + num2) * sign;
}
{
    double num1 = 0.0;
    double num2 = 0.0;
    double point = 0.1;
    int sign = 1;

    int len = strlen(str) + 1;
    *endstr = new char[len];
    memset(*endstr, 0, len);

    if (*str == '-')
    {
        sign = -1;
        ++str;
    }

    if (!isdigit(*str))
    {
        strcpy(*endstr, str);
        return 0.0;
    }
    while (*str && isdigit(*str))
    {
        if (*str == '.')
        {
            ++str;
            while (*str && isdigit(*str))
            {
                num2 += point * ((*str) - '0');
                point *= 0.1;
                ++str;
            }
            strcpy(*endstr, str);
            break;
        }
        else
        {
            num1 = 10 * num1 + *str - '0';
            str++;
            if (!*str || !isdigit(*str))
            {
                strcpy(*endstr, str);
                break;
            }
        }
    }
    
    return (num1 + num2) * sign;
}

 

 

 

 

参考如下文章,修正了源码中的部分错误。

atoi atof源码

strtoul, strtol实现代码

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值