реализация atoi в C
Я не могу понять следующее atoi
код реализации, в частности эта строка:k = (k<<3)+(k<<1)+(*p)-'0';
код:
int my_atoi(char *p) {
int k = 0;
while (*p) {
k = (k<<3)+(k<<1)+(*p)-'0';
p++;
}
return k;
}
может кто-нибудь объяснить это мне ?
другой вопрос: каким должен быть алгоритм atof
реализация ?
4 ответов
k = (k << 3) + (k << 1);
означает
k = k * 2³ + k * 2¹ = k * 8 + k * 2 = k * 10
это поможет?
на *p - '0'
term добавляет значение следующей цифры; это работает, потому что C требует, чтобы символы цифр имели последовательные значения, так что '1' == '0' + 1
, '2' == '0' + 2
, etc.
что касается вашего второго вопроса (atof
), это должен быть его собственный вопрос, и это тема для диссертации, а не что-то простое для ответа...
<<
бит смещение, (k<<3)+(k<<1)
is k*10
, написанный кем-то, кто хотя и умнее компилятора (ну, он ошибался...)
(*p) - '0'
- это вычитания 0
от символа, указанного p
, фактически превращая символ в число.
Я надеюсь, что вы можете выяснить остальное.. просто помните, как работает десятичная система.
обратите внимание, что это стандартный, соответствующий atoi
реализация. Извините, что не цитирую стандарт, но это будет работать так же хорошо (от:http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/ )
функция сначала отбрасывает столько пробелов (как в isspace) по мере необходимости, пока первый символ без пробелов не будет найдено. Затем, начиная с этого символа, берет необязательный инициал плюс или минус знак, за которым следует как можно больше базовых-10 цифр, и интерпретирует их как числовое значение.
в строка может содержать дополнительные символы после тех, которые формируют интегральное число, которое игнорируется и не влияет на поведение этой функции.
если первая последовательность символов без пробелов в str не является действительное интегральное число, или если такая последовательность не существует, потому что либо str пуст или содержит только пробелы, без преобразования выполняется и возвращается ноль.
#include <stdio.h>
#include <errno.h>
#include <limits.h>
double atof(const char *string);
int debug=1;
int main(int argc, char **argv)
{
char *str1="3.14159",*str2="3",*str3="0.707106",*str4="-5.2";
double f1,f2,f3,f4;
if (debug) printf("convert %s, %s, %s, %s\n",str1,str2,str3,str4);
f1=atof(str1);
f2=atof(str2);
f3=atof(str3);
f4=atof(str4);
if (debug) printf("converted values=%f, %f, %f, %f\n",f1,f2,f3,f4);
if (argc > 1)
{
printf("string %s is floating point %f\n",argv[1],atof(argv[1]));
}
}
double atof(const char *string)
{
double result=0.0;
double multiplier=1;
double divisor=1.0;
int integer_portion=0;
if (!string) return result;
integer_portion=atoi(string);
result = (double)integer_portion;
if (debug) printf("so far %s looks like %f\n",string,result);
/* capture whether string is negative, don't use "result" as it could be 0 */
if (*string == '-')
{
result *= -1; /* won't care if it was 0 in integer portion */
multiplier = -1;
}
while (*string && (*string != '.'))
{
string++;
}
if (debug) printf("fractional part=%s\n",string);
// if we haven't hit end of string, go past the decimal point
if (*string)
{
string++;
if (debug) printf("first char after decimal=%c\n",*string);
}
while (*string)
{
if (*string < '0' || *string > '9') return result;
divisor *= 10.0;
result += (double)(*string - '0')/divisor;
if (debug) printf("result so far=%f\n",result);
string++;
}
return result*multiplier;
}
интересно, что man-страница для atoi не указывает на настройку errno, поэтому, если вы говорите о любом числе > (2^31)-1, вам не повезло и аналогично для чисел меньше -2^31 (предполагая 32-битный int). Ты получишь ответ, но это будет не то, что ты хочешь. Вот один, который может принимать диапазон от- ((2^31)-1) до(2^31)-1 и возвращать INT_MIN (- (2^31)), если ошибка. ошибки тут могут быть проверены, чтобы увидеть, если он засорился.
#include <stdio.h>
#include <errno.h> /* for errno */
#include <limits.h> /* for INT_MIN */
#include <string.h> /* for strerror */
extern int errno;
int debug=0;
int atoi(const char *c)
{
int previous_result=0, result=0;
int multiplier=1;
if (debug) printf("converting %s to integer\n",c?c:"");
if (c && *c == '-')
{
multiplier = -1;
c++;
}
else
{
multiplier = 1;
}
if (debug) printf("multiplier = %d\n",multiplier);
while (*c)
{
if (*c < '0' || *c > '9')
{
return result * multiplier;
}
result *= 10;
if (result < previous_result)
{
if (debug) printf("number overflowed - return INT_MIN, errno=%d\n",errno);
errno = EOVERFLOW;
return(INT_MIN);
}
else
{
previous_result *= 10;
}
if (debug) printf("%c\n",*c);
result += *c - '0';
if (result < previous_result)
{
if (debug) printf("number overflowed - return MIN_INT\n");
errno = EOVERFLOW;
return(INT_MIN);
}
else
{
previous_result += *c - '0';
}
c++;
}
return(result * multiplier);
}
int main(int argc,char **argv)
{
int result;
printf("INT_MIN=%d will be output when number too high or too low, and errno set\n",INT_MIN);
printf("string=%s, int=%d\n","563",atoi("563"));
printf("string=%s, int=%d\n","-563",atoi("-563"));
printf("string=%s, int=%d\n","-5a3",atoi("-5a3"));
if (argc > 1)
{
result=atoi(argv[1]);
printf("atoi(%s)=%d %s",argv[1],result,(result==INT_MIN)?", errno=":"",errno,strerror(errno));
if (errno) printf("%d - %s\n",errno,strerror(errno));
else printf("\n");
}
return(errno);
}