(本片文章参考与借鉴了公众号编程珠玑关于atoi函数的文章,原文链接https://mp.weixin.qq.com/s/CBvdzYrjt81Ko_a1LROusw)
首先是百度百科关于atoi函数的介绍
atoi (表示 ascii to integer)是把字符串转换成整型数的一个函数,应用在计算机程序和办公软件中。int atoi(const char *nptr) 函数会扫描参数 nptr字符串,会跳过前面的空白字符(例如空格,tab缩进)等。
概括一下就是可以把一个字符串转换成相应的整型数,并且可以自动跳过字符串前面的空格
如“ 123”可以转换成123;
“-123”可以转换成-123;
“+123”可以转换成123;
下面是自己实现atoi函数的代码
我们需要考虑以下几种情况
- 如果开头是负号,则标记为负数;正号或数值,则标记为正数
- 跳过开头的空格,从第一个有效字符开始
- 使用更大类型存储计算值,如果负数比INT_MIN还小或正数比INT_MAX还大,则表明溢出,返回INT_MIN或INT_MAX,或者在下次计算之前与INT_MIN/10或INT_MAX/10比较
- 使用全局变量记录出错情况,区别正常转换为0或最大最小值
- 遇到非数值时即退出
(此处源码来自公众号编程珠玑,原文https://mp.weixin.qq.com/s/CBvdzYrjt81Ko_a1LROusw)
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#define NULL_PTR_ERR 1
#define ERANGE 2
int errCode = 0;
int my_atoi(char* str) {
int negative = 0;
char c = 0;
/*计算结果存储*/
long long ret = 0;
errCode = 0;
if(NULL == str)
{
errCode = NULL_PTR_ERR;
return 0;
}
/*跳过开始的空格*/
while(' ' == (*str))
str++;
/*跳过空格之后,到达了字符串结尾,则退出*/
if(0 == *str)
return 0;
/*负数*/
if(*str == '-' )
{
negative = 1;
str++;
}
/*正数*/
else if(*str == '+')
{
negative = 0;
str++;
}
/*正数*/
else if(isdigit(*str))
{
negative = 0;
}
/*如果不是以上内容,则直接退出*/
else
{
return 0;
}
while(isdigit(*str))
{
/*计算结果*/
ret = ret*10 + *str -'0';
/*如果发现结果大于INT_MAX或者小于INT_MIN,则溢出,返回最值*/
if(ret > (negative?-(long long )INT_MIN:INT_MAX))
{
/*溢出,返回最大值*/
errCode = ERANGE;
return negative?INT_MIN:INT_MAX;
}
str++;
}
/*根据正负号返回正确的结果*/
return negative?-ret:ret;
}
int main(void)
{
/*只有一个负号*/
int result = my_atoi("-");
printf("-:%d,errCode:%d\n\n",result,errCode);
/*空指针*/
result = my_atoi(NULL);
printf("NULL:%d,errCode:%d\n\n",result,errCode);
/*空字符串*/
result = my_atoi(" ");
printf("(empty string) :%d,errCode:%d\n\n",result,errCode);
/*负数*/
result = my_atoi("-1");
printf("-1:%d,errCode:%d\n\n",result,errCode);
/*负数溢出*/
result = my_atoi(" -11111111111");
printf(" -11111111111:%d,errCode:%d\n\n",result,errCode);
/*正数*/
result = my_atoi("+123");
printf("+123:%d,errCode:%d\n\n",result,errCode);
/*正数溢出*/
result = my_atoi("+123111111111111111");
printf("+123111111111111111:%d,errCode:%d\n\n",result,errCode);
/*字母开头*/
result = my_atoi("a12345");
printf("a12345:%d,errCode:%d\n\n",result,errCode);
/*字母开头,字母空格混用*/
result = my_atoi(" a b c 123d45");
printf(" a b c 123d45:%d,errCode:%d\n\n",result,errCode);
return 0;
}
运行结果如下
从结果上来看,好像能应对所有的状况了,但是没有办法应对开头字母的情况。
下面我自己稍微改进了一下代码使其适应开头字母空格混合情况
int my_atoi(char *str)
{
int negative = 0;//0表示正数,1表示负数
long long ret = 0;
errCode = 0;
//首先判断空
if (str == NULL)
{
errCode = NULL_PTR_ERR;
return 0;
}
//跳过空格--atoi只会跳过空格
while(!isdigit(*str))
{
if('0' == *str)
{
return 0;
}
else if('-' == *str)
{
negative = 1;
str++;
break;
}
else if('+' == *str)
{
negative = 0;
str++;
break;
}
else if(isdigit(*str))
{
negative = 0;
break;
}
else
{
str++;
}
}
while(isdigit(*str))
{
//计算结果,*str - '0'是通过ASCII码计算相对应的数值
ret = ret*10 + *str - '0';
//如果发现结果大于INT_MAX或者小于INE_MIN,则溢出,返回最值
if(ret >(negative?-(long long)INT_MIN:INT_MAX))
{
errCode = ERANGE;
return negative?INT_MIN:INT_MAX;
}
str++;
}
return negative?-ret:ret;
}
int main(void)
{
/*只有一个负号*/
int result = my_atoi("-");
printf("-:%d,errCode:%d\n\n",result,errCode);
/*空指针*/
result = my_atoi(NULL);
printf("NULL:%d,errCode:%d\n\n",result,errCode);
/*空字符串*/
result = my_atoi(" ");
printf("(empty string) :%d,errCode:%d\n\n",result,errCode);
/*负数*/
result = my_atoi("-1");
printf("-1:%d,errCode:%d\n\n",result,errCode);
/*负数溢出*/
result = my_atoi(" -11111111111");
printf(" -11111111111:%d,errCode:%d\n\n",result,errCode);
/*正数*/
result = my_atoi("+123");
printf("+123:%d,errCode:%d\n\n",result,errCode);
/*正数溢出*/
result = my_atoi("+123111111111111111");
printf("+123111111111111111:%d,errCode:%d\n\n",result,errCode);
/*字母开头*/
result = my_atoi("a12345");
printf("a12345:%d,errCode:%d\n\n",result,errCode);
/*字母开头,字母空格混用*/
result = my_atoi(" a b c 123d45");
printf(" a b c 123d45:%d,errCode:%d\n\n",result,errCode);
return 0;
}
上述代码会在一开始跳过所有的特殊字符(非‘+’、‘-’、十进制数值)
打印结果如下