为什么我对K&R练习2-3的解决方案不起作用?

时间:2018-06-30 20:55:00

标签: c

我正在尝试解决 C编程语言一书中的练习2-3,但是我的解决方案无法正常工作,而且我找不到我做错了什么。练习表明编写一个函数,该函数接受包含十六进制数字的字符串,并将该数字作为int返回。

这是我的代码:

#include <stdio.h>
#include <ctype.h>
#include <math.h>

int htoi(char *s);

int main() {
    char s[5];
    scanf("%s", s);
    printf("%d", htoi(s));  
}

int htoi(char *s) {
    int length, num = 0, i;
    char c = 'A';
    for (length = 0; c >= '0' && c <= '9' || c >= 'A' && c <= 'F'; length++)
        c = toupper(s[length]);
    for (i = 0; i <= length; i++) {
        c = toupper(s[i]);
        if (c >= '0' && c <= '9')
            num += (c - '0') * pow(16, length - i);
        else if (c >= 'A' && c <= 'F')
            num += (c - 'A' + 10) * pow(16, length - i);
    }
    return num;
}

为什么不起作用?

2 个答案:

答案 0 :(得分:0)

您需要将pow(16, length - i)更改为pow(16, length - i - 2)

“为什么2?”你可能会问。

那么,您需要学习如何调试程序。首先,您的length似乎计算不正确。打印该值,您会发现它实际上比预期的多一。通常,C程序员在谈论字符串的长度时不计算'\0'终止符,而标准函数strlen也不这样。

因此,应在计算长度后从长度中删除1。然后这将是有意义的。例如,4 = 4×10 1和40 = 4×10 1。位置n上的数字应提高到幂n-1。之后,您使用pow(16, length - i - 1)。注意,当我们有正确的长度时,它是1而不是2。

您对代码的其他评论

除非有特殊原因,否则我不会编写自定义函数来计算长度。而是使用strlen并稍后检查正确性。在此程序中,您似乎可以假定该字符串始终正确。所以我会这样写:

int htoi(char * s) {
    int length = strlen(s), num = 0, i;

    for (i = 0; i < length; i++) {
        int factor = pow(16, length - i - 1), digit;
        int c = toupper(s[i]);
        if (c >= '0' && c <= '9')
            digit = c - '0';
        else if (c >= 'A' && c <= 'F')
            digit = c - 'A' + 10;
        num += digit * factor;
    }
    return num;
}

我也对其进行了重构。

答案 1 :(得分:0)

您的代码中存在多个问题:

  • 输入缓冲区太小,您没有将其大小传递给scanf()。如果用户在换行符之前键入四个以上的字符,则您将具有未定义的行为。使用fgets()或至少指定要存储的最大字符数scanf("%4s", s)更为安全。
  • 您应该测试scanf()的返回值,以防止无效输入(例如,从空文件重定向)时出现不确定的行为。
  • htoi中的第一个循环试图计算介于AF之间的数字或字母的字符数,但是它不正确,因为它在计算的结果中包括第一个不匹配的字符length。此外,如果用户键入char之类的外来字符,则在默认情况下对é进行签名的平台上,它具有未定义的行为。
  • 依靠浮点算法进行此计算既浪费资源,又可能不正确。有一种更简单的方法,您可以将num的当前值乘以16并加上当前十六进制数字的值。在您的方法中,因子应为pow(16, length - i -); if length`已经正确计算。

这是更正的版本:

#include <ctype.h>
#include <stdio.h>

int htoi(const char *s);

int main() {
    char s[100];
    if (fgets(s, sizeof s, stdin))
        printf("%d\n", htoi(s));
    return 0;
}

int htoi(const char *s) {
    unsigned int num = 0;
    int i;
    for (i = 0; isxdigit((unsigned char)s[i]); i++) {
        if (c >= '0' && c <= '9')
            num = num * 16 + c - '0';
        else
            num = num * 16 + 10 + toupper(c) - 'A';
    }
    return num;
}