我写了一个函数,意思是像
<stdlib.h>
函数atoi
:
int _atoi(char *s)
{
int i, neg = 1, n = 0;
for (i = 0; s[i] != '\0'; i++)
{
if ((s[i] >= '0') && (s[i] <= '9'))
n = n * 10 + (s[i] - '0');
else if (s[i] == '-')
neg *= -1;
}
n *= neg;
return (n);
}
当我用类似的东西运行它时
nb = _atoi(" + + - -98 Battery Street; San Francisco, CA 94111 - USA ");
printf("%d\n", nb);
输出为
-9894111
但是使用类似的代码:
int _atoi(char *s)
{
int sign = 1, i = 0, res = 0;
while (!(s[i] <= '9' && s[i] >= '0') && s[i] != '\0')
{
if (s[i] == '-')
sign *= -1;
i++;
}
while (s[i] <= '9' && s[i] >= '0' && s[i] != '\0')
{
res = (res * 10) + (s[i] - '0');
i++;
}
res *= sign;
return (res);
}
输出为
98
。
这是真正的 atoi
函数返回的内容。
使后者忽略
8
(即-
和94111
)之后的所有内容的两个代码之间有什么区别?
第一个代码的循环条件是
s[i] != '\0'
。这意味着循环将一直运行到字符串末尾,而不管之前是否存在未转换的字符。
另一方面,第二个代码中最后一个循环的循环条件是
s[i] <= '9' && s[i] >= '0' && s[i] != '\0'
。这将使循环在第一个不是数字的字符处停止。
因此,第一个代码将在
94111 -
之后的非数字字符后看到 98
,而第二个代码则不会。
第一个函数迭代整个字符串,将存在的所有数字组合成一个数字,即使它们被其他字符分隔。它还将任何出现的
-
解释为应用于结果数字的负号。这绝对不是atoi()
的行为。
第二个函数首先跳过任何非数字,只测试
-
符号被解释为改变结果的符号。然后它迭代数字,直到找到非数字或字符串的末尾。因此它只解释字符串中出现的第一个数字,可能多次否定它。这会为您的输入字符串产生不同的值,但仍然不是atoi()
. 的行为
标准函数
atoi
首先跳过任何空白字符(由 isspace()
定义,然后接受一个可选符号(单个 +
或 -
字符),然后解析任何紧随其后的数字并停止在第一个非数字。对于测试字符串,它返回0
.
建议在
strtol()
上使用atoi()
以避免在包含超出类型int
范围的整数表示的字符串上出现未定义的行为。
这里是
atoi()
的简单实现,具有定义的行为:
#include <limits.h>
#include <stdlib.h>
int atoi(const char *s) {
long n = strtol(s, NULL, 10);
return n < INT_MIN ? INT_MIN :
n > INT_MAX : INT_MAX : n;
}
如果不使用
<stdlib.h>
就想实现自己的功能,可以使用:
#include <ctype.h>
#include <limits.h>
int my_atoi(const char *s) {
int res = 0;
while (isspace((unsigned char)*s)) {
s++;
}
if (*s == '-') {
s++;
while (*s >= '0' && *s <= '9') {
int digit = *s++ - '0';
if (res < INT_MIN / 10
|| res == INT_MIN / 10 && -digit < INT_MIN % 10) {
res = INT_MIN;
} else {
res = res * 10 - digit;
}
}
} else {
if (*s == '+') {
s++;
}
while (*s >= '0' && *s <= '9') {
int digit = *s++ - '0';
if (res > INT_MAX / 10
|| res == INT_MAX / 10 && digit > INT_MAX % 10) {
res = INT_MAX;
} else {
res = res * 10 + digit;
}
}
}
return res;
}