字符串转数字看似很简单,其实很多细节需要把握,这里涉及到代码完整性:功能测试、边界检测和负面测试。如果要把所有的细节都考虑到是不太容易的。
本博客启发于剑指offer的最后一章的第一个面试案例。
我想大家都知道用n=n*10+c-‘0’的方式来进行转换,这里就直接进行分析了。
功能测试:
出现+-号,能否正确识别并计算出正确结果。
边界检测:
如果发生溢出情况怎么办,字符串超出了int范围?
负面检测:
1、字符串为空“”
2、输入指针为NULL
3、含有非数字字符
4、开头的+、-号之后接着'\0'
5、小数点(新添加,代码未实现)
由于可能出现的负面输入以及溢出情况,我们需要对结果进行判断,这里介绍一下三种错误处理方式:返回值、全局变量、异常。
返回值:和系统API一致; 但是不能方便的使用返回结果,并且会有二义性。
全局变量:用全局变量表示错误状态,能方便使用结果; 但是程序员可能会忘记检查全局变量。
异常:可以为不同的出错原因定义不同该异常类型,逻辑清晰明了; 有些语言不支持,同时对性能有一定程度上的负面影响。
这里附上全局变量和异常处理的两种代码供参考:
全局变量:
enum Status{Valid = 0, Invalid, OutOfRange};
int g_status = Invalid;
int atoi(char* str)
{
if(str != NULL && *str != '\0')
{
g_status = Invalid;
//这里用long long是为了判断它的越界;
long long num = 0;
char *tmp = str;
int flag = 1;
//判断开头的符号;
if(*tmp == '-')
{
flag = -1;
++tmp;
}
else if(*tmp == '+')
++tmp;
//以免只有符号没有数字;
if(*tmp != '\0')
{
while(*tmp != '\0')
{
if(*tmp >= '0' && *tmp <= '9')
{
//如果num不是long long,这里就需要多计算一次;
num = num*10 + flag * (*tmp - '0');
if(flag && num > 0x7FFFFFFF)
{
g_status = OutOfRange;
return 0;
}
if(flag == 0 && num < 0x80000000)
{
g_status = OutOfRange;
return 0;
}
}
else
{
return 0;
}
}
}
g_status = Valid;
return num;
}
}
异常:
int atoi(char* str)
{
if(str != NULL && *str != '\0')
{
//这里用long long是为了判断它的越界;
long long num = 0;
char *tmp = str;
int flag = 1;
//判断开头的符号;
if(*tmp == '-')
{
flag = -1;
++tmp;
}
else if(*tmp == '+')
++tmp;
//以免只有符号没有数字;
if(*tmp != '\0')
{
while(*tmp != '\0')
{
if(*tmp >= '0' && *tmp <= '9')
{
//如果num不是long long,这里就需要多计算一次;
num = num*10 + flag * (*tmp - '0');
if(flag && num > 0x7FFFFFFF)
throw range_error("Error: out of range!");
if(flag == 0 && num < 0x80000000)
throw range_error("Error: out of range!");
}
else
{
throw invalid_argument("Error: invalid input!");
}
}
}
else
throw invalid_argument("Error: invalid input!");
return num;
}
else
throw invalid_argument("Error: invalid input!");
}