题目:
请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。
当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。
该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0。
说明:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
用了两种解法:
解法一:看起来就比较复杂,没有认真思考仔细审题就是这个结果,费时费力。
int myAtoi(char * str)
{
int int_max = 2147483647;
int int_min = -2147483648;
int num = 0,str_value = 0;
char plus_minus = 1,time = 0;
/*没有对字符串做模块的划分,整体循环去判断,需要多增加判断的条件。*/
while( *str != '\0'){
if(*str == ' '){
if(num == 0 && time == 0)
str++;
else
break;
}else if(*str == '+'){
if(num == 0 && time == 0){
plus_minus = 1;
str++;
time++;
}else{
break;
}
}else if(*str == '-'){
if(num == 0 && time == 0){
plus_minus = 0;
str++;
time++;
}else{
break;
}
}else if(*str >= '0' && *str <= '9'){
str_value = (int)(*str) - 48;
/*采用int类型去判断是否溢出,只能判断7位数(不然会导致溢出),最后第8位要单独拿出来做判断*/
if(num < int_min/10 || (num == int_min/10 && str_value >= 8)){
return int_min;
break;
}else if(num > int_max/10 || (num == int_max/10 && str_value >= 7)){
return int_max;
break;
}
/*计算值的时候要对正负进行判断,并且要注意num是否为0值*/
if(plus_minus == 0){
num = -(num*10 + str_value);
if(num != 0)
plus_minus = 1;
}else{
if(num >= 0)
num = num*10 + str_value;
else if(num < 0)
num = num*10 - str_value;
}
str++;
time++;
}else{
break;
}
}
return num;
}
解法二:模块划分得比较清楚,易读性高。
仔细解读题目就可以知道,在有效字符之前(‘0’~‘9’)只允许空格和‘+’‘-’号出现,且正负符号只能出现在有效数字的前面,也就是说只允许出现“空格”+“正负符号”+“有效字符”的组合,其余不符合条件的情况,返回0.
int myAtoi(char * str)
{
char plus_minus = 1;
long int num = 0;
while(*str == ' '){
str++;
}
if(*str == '-'){
plus_minus = 0;
str++;
}else if(*str == '+'){
str++;
}
while(*str != '\0'){
if(*str >= '0' && *str <= '9'){
num = (num*10 + (*str-'0'));
/*这里采用了long int类型的数据来存放转换后的值,简化了对溢出的判断*/
if(num > 0x7fffffff)
return plus_minus ? 0x7fffffff:0x80000000;
str++;
}else{
break;
}
}
return plus_minus ? num:-num;
}
值得注意的地方:
0x7fffffff 表示正数:2147483647;
0x80000000 表示负数:-2147483648;
学过计算机基础的都知道,计算机中:
正数:原码 = 反码 = 补码;
负数:反码 = 原码取反;补码=反码+1;
按照这样的规律理解0x80000000对应十进制的-0,但是打印出来确是-2147483648;
原因是在十六进制中负数的二进制原码的最高位是符号位,后面的31位为序号位,不是值。序号位算出来的值表示负数中从最小值开始到0的位置数。比如:
int类型的取值范围为[-2 ^31 ~ 2 ^31]
0x800000000
原码 1000 0000 0000 0000 0000 0000 0000 0000
最高位为1,为负数,序号位的值为0;表示负数范围内从左到右第一位,即-2 ^31。
再来看看0xFFFFFFFF
原码 1111 1111 1111 1111 1111 1111 1111 1111
最高位为1 ,为负数,序号位为第(2 ^ 31)-1位 (111 1111 1111 1111 1111 1111 1111 1111=(2 ^ 31-1) 所以0xFFFFFFFF为负数从小到大 第2^31-1位 ,
即-2 ^ 31+2 ^ 31 - 1= -1