本题要求自己实现atoi函数,输入为一个string,输出为相应的int型integer.主要考察能否全面地考虑到输入的不同情况。比如以下的一些情况:
1. 输入"" 期待输出0
2. 输入" " 期待输出0
3. 输入" -a4" 期待输出0
4. 输入" -" 期待输出0
5. 输入" 90 " 期待输出90
6. 输入"-3 " 期待输出-3
7. 输入"5abc3" 期待输出5
8. 输入"004" 期待输出4
9. 输入"0.3" 期待输出0
10. 输入"2147483648" 期待输出 2147483647(题目给定了一个溢出的范围为[INT_MIN, INT_MAX],这个数溢出了,所以输出INT_MAX,取值为2147483647)
11. 输入"-2147483649" 期待输出 2147483647(题目给定了一个溢出的范围为[INT_MIN, INT_MAX],这个数溢出了,所以输出INT_MIN,取值为-2147483648)
代码如下
class Solution {
public:
int atoi(const char *str) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
long long result = 0;
int index=0;
bool is_positive=true;
long long long_int_min_abs=INT_MIN;
long_int_min_abs=0-long_int_min_abs;
//std::cout<<"a="<<a<<std::endl;
//std::cout<<"a="<<-INT_MIN<<std::endl;
while(str[index]==' '){
index++;
}
if(str[index]=='\0') { //空串
return 0;
}
if(str[index]=='+') {//有正号
is_positive=true;
index++;
}
else if(str[index]=='-') {//有负号
is_positive=false;
index++;
}
else if( (str[index]-'0'>=0) && (str[index]-'0'<=9) ) {//无正号无负号,是数字
is_positive=true;
}
else {
return 0; //无法做任何转换的不规则串
}
while((str[index]-'0'>=0)&&(str[index]-'0'<=9)) {
int digit=str[index]-'0';
result=result*10+digit;
index++;
//std::cout<<"digit="<<digit<<",result="<<result<<std::endl;
if((result>INT_MAX)&&(is_positive==true))
return INT_MAX;
if((result>long_int_min_abs)&&(is_positive==false))//等价于result<abs(INT_MIN)
return INT_MIN;
}
if(is_positive==false)
result=-result;
return (int)result;
}
};
小结:
(1) 考虑清楚各种情况
(2) 溢出的处理需要小心。首先使用了long long型变量作为中间变量result来存储结果,这样避免了发生int型的溢出。
(3) 溢出的处理需要小心。其次注意第9行和第10行
long long long_int_min_abs=INT_MIN;
long_int_min_abs=0-long_int_min_abs;
这么写是因为如果写为
long long long_int_min_abs=0-INT_MIN;
的话,得到的结果不是希望得到的2147483648而是2147483647,猜测可能是因为在没有转化为long long时,INT_MIN会由于int的溢出,所以0-INT_MIN得到的是INT_MAX而不是INT_MIN的绝对值。(我的测试平台是mac 64位Xcode。)
(4) 溢出是什么?
溢出简单地说,就是要表示的数太巨大了,变量类型装不下了。
在C++中,整型的溢出分为signed 和unsigned 2种情况。unsigned在面对表示的巨大的数的情况下,是有固定的规则的,所以也可以叫做unsigned不会溢出。而signed是undefined behavior,即是未定义的行为。
以unsigned int为例来看看,在mac 64中,unsigned int的取值范围为[0~4294967295].
unsigned int aa=4294967295;
aa=aa+1; //结果为aa=0
aa=aa+1; //结果为aa=1
aa=4294967295+1; //结果为aa=0
所以,遇到一个极大的unsigned int数,只需要用它取模4294967296就知道了它的最终值。
在signed int中,由于历史原因,表示正负数的方式有一些差异,所以没法给出一个确定的结果。很多情况是,两个巨大的正数相加,结果是个负数。这就是发生了溢出。
搜到一份linux的atoi函数的源码,基本思路也差不多,贴在下面。
long __cdecl atol(
const char *nptr
)
{
int c; /* current char */
long total; /* current total */
int sign; /* if '-', then negative, otherwise positive */
/* skip whitespace */
while ( isspace((int)(unsigned char)*nptr) )
++nptr;
c = (int)(unsigned char)*nptr++;
sign = c; /* save sign indication */
if (c == '-' || c == '+')
c = (int)(unsigned char)*nptr++; /* skip sign */
total = 0;
while (isdigit(c)) {
total = 10 * total + (c - '0'); /* accumulate digit */
c = (int)(unsigned char)*nptr++; /* get next char */
}
if (sign == '-')
return -total;
else
return total; /* return result, negated if necessary */
}
update: 2014-12-16
下面的解法没有使用long来存当前的result,而是使用int ,在result可能累加过界超过INT_MAX的时候就根据情况返回INT_MAX或者INT_MIN了。
class Solution {
public:
int atoi(const char *str) {
//space
//validate 0~9
//+-
//0012 vs 1002
//INTMAX
int result = 0;
bool isNegative = false;
while(*str == ' ')
str++;
if(*str == '+')
str++;
else if(*str == '-') {
isNegative = true;
str++;
}
while(*str != '\0') {
if (*str - '0' == 0 && result == 0) {
str++;
continue;
}
if (*str - '0' < 0 || *str - '9' > 0)
return isNegative? -result: result;
if (result > INT_MAX / 10)
return isNegative? INT_MIN : INT_MAX;
result *= 10;
if ((*str - '0') > (INT_MAX - result))
return isNegative? INT_MIN : INT_MAX;
result = result + *str - '0';
str++;
}
return isNegative? -result : result;
}
};