C语言 这两个函数之间的区别是什么,后者不考虑参数中的所有字符串,而第一个考虑

jv4diomz  于 2023-03-17  发布在  其他
关注(0)|答案(2)|浏览(93)

我写了一个函数,其作用类似于<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)?

jvlzgdj9

jvlzgdj91#

第一个函数对整个字符串进行迭代,将所有出现的数字组合成一个数字,即使这些数字被其他字符分隔,它也将任何出现的-解释为负号,以应用于结果数字,这绝对不是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++;
        // isdigit((unsigned char)*s) is guaranteed to be
        //   equivalent to `(*s >= '0' && *s <= '9')`
        // isdigit(*s) would have undefined behavior if `char`
        //   is signed and `*s` is negative.
        // I am using the explicit test for clarity
        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;
}
pvcm50d1

pvcm50d12#

第一个代码的循环条件是s[i] != '\0',这意味着循环将一直运行到字符串末尾,而不管在此之前是否存在未转换的字符。
另一方面,第二个代码中最后一个循环的循环条件是s[i] <= '9' && s[i] >= '0' && s[i] != '\0',这将使循环在第一个不是数字的字符处停止。
因此,第一个代码将在98之后的非数字字符之后看到94111 -,而第二个代码则不会。

相关问题