我无法理解以下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
实施的算法应该是什么?
答案 0 :(得分:31)
<<
是位移,(k<<3)+(k<<1)
是k*10
,由一个认为他比编译器更聪明的人写的(好吧,他错了......)
(*p) - '0'
从0
指向的字符中减去字符p
的值,有效地将字符转换为数字。
我希望你能弄明白其余的......只记得小数系统是如何工作的。
以下是标准函数atoi
的规范。很抱歉没有引用标准,但这样可以正常工作(来自:http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/)
该函数首先丢弃尽可能多的空白字符(如
isspace
}必要时直到第一个非空格字符为止 找到。然后,从这个字符开始,采用可选的初始值 加号或减号后跟最多10位数字,以及 将它们解释为数值。该字符串可以包含其他字符后形成的字符 整数,被忽略并且对行为没有影响 这个功能。
如果
str
中的第一个非空白字符序列不是a 有效的整数,或者如果没有这样的序列,则可能str
为空或仅包含空格字符,不包含转换 执行并返回零。
答案 1 :(得分:26)
k = (k << 3) + (k << 1);
装置
k = k * 2³ + k * 2¹ = k * 8 + k * 2 = k * 10
这有帮助吗?
*p - '0'
字词会添加下一个数字的值;这是有效的,因为C要求数字字符具有连续值,以便'1' == '0' + 1
,'2' == '0' + 2
等。
关于你的第二个问题(atof
),这应该是它自己的问题,而且它是论文的主题,而不是简单的回答......
答案 2 :(得分:1)
#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;
}
答案 3 :(得分:0)
有趣的是,atoi的手册页并不表示errno的设置,所以如果你正在说任何数字&gt; (2 ^ 31)-1,你运气不好,同样数字小于-2 ^ 31(假设32位int)。你会得到一个答案,但它不会是你想要的。如果出错,这里可以采用 - ((2 ^ 31)-1)到(2 ^ 31)-1的范围,并返回INT_MIN( - (2 ^ 31))。然后可以检查errno以查看它是否溢出。
#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);
}
答案 4 :(得分:0)
这是我的实现(已成功测试包含和以字母,+,-和零开头的案例)。 我尝试对 Visual Studio 中的 atoi 函数进行反向工程。如果输入字符串仅包含数字字符,则可以在一个循环中实现。但是它变得复杂,因为您应该注意-, + 和字母。
dplyr::recode_factor
答案 5 :(得分:0)
关于here中的atoi()提示代码:
并基于atoi(),我对atof()的实现:
[具有与原始代码相同的限制,不检查长度等]
double atof(const char* s)
{
double value_h = 0;
double value_l = 0;
double sign = 1;
if (*s == '+' || *s == '-')
{
if (*s == '-') sign = -1;
++s;
}
while (*s >= 0x30 && *s <= 0x39)
{
value_h *= 10;
value_h += (double)(*s - 0x30);
++s;
}
// 0x2E == '.'
if (*s == 0x2E)
{
double divider = 1;
++s;
while (*s >= 0x30 && *s <= 0x39)
{
divider *= 10;
value_l *= 10;
value_l += (double)(*s - 0x30);
++s;
}
return (value_h + value_l/divider) * sign;
}
else
{
return value_h * sign;
}
}