微软面试题之一,难度系数低。
题目描述如下:输入一个表示整数的字符串,把该字符串转换成整数并输出。
例如输入字符串"345",则输出整数345。
逻辑分析:
1、对于面试者来说,遇到这种题,算是很幸运的,比起思维灵活度,本题更加注重基础,也就是说,代码的稳定性,健壮性一定要好。对C/C++比较熟悉的读者应该很快会想到一个函数:atoi,没错,标准库中的atoi就是将字符串转为整数的函数。虽然如此,但却很少有人尝试去了解atoi这个函数的内部实现,窃以为,atoi的实现,其实和str*系列函数同等重要。
2、说到稳定性,就要考虑几个容易引起问题的地方,函数模型int atoi(char* str);,那么第一点要考虑的,当然是str是否为空。另外,str中的字符只可能存在三种情况:- | + | [0..9],如果存在其他字符,那么则视为非法字符。最后一点,也是最容易忽略的,要考虑溢出问题。
给出代码:
#include <stdio.h>
#include <limits.h>
int atoi(char *str)
{
bool neg = true;
char *p = str;
int num = 0;
if(str == NULL)
{
printf("字符串为空!你TM是在逗我吗?\n");
return 0;
}
if(*p == '-')
{
p++;
neg = false;
}else if(*p == '+')
{
p++;
}
while(*p != '\0')
{
if(*p>='0' && *p <= '9')
{
num = num * 10 + (*p - '0');
if(num > INT_MAX)
{
printf("溢出!\n");
return 0;
}
}
else
{
printf("错误!含非法字符\n");
return 0;
}
p++;
}
if(neg == false)
num = -num;
return num;
}
int main()
{
char str[4][10] = {"123456789","+23","-45","XiaoJ8"};
for(int i=0; i<4;i++)
{
printf("%d\n",atoi(str[i]));
}
return 0;
}
输出:
3、乍看起来,我们好像完成了任务,但是实际上,当我写完上述代码之后,立刻反悔了。很多读者应该也察觉到了,上述代码有一个很严重的漏洞,我们都知道因为补码的形式存储,负整数的绝对值上限是要比正整数上限大1的,而我们判断的分支,显然漏掉了负上限。再仔细考虑,就会发现,其实判别代码从一开始就错了,而且是完全错了。高级语言不是汇编,我们无法通过CF,OF之类的(无符号当然是CF)标志位来判别,而在我们的程序中,num是永远不可能大于INT_MAX的,因为当num超过了这个值,则会自动溢出,变为一个很小的值,再去比较显然没有意义。正确的处理,是要对比计算前后的num,如果计算后的值小于计算前,显然发生了溢出(想想为什么)。
另外一种处理方式,就是从位数进行比较,显然后者略麻烦一些,倒也不失为一种思路。
代码不再纠正,后续工作由读者完成。