【问题标题】:Hexadecimal input function calculates wrong values十六进制输入函数计算错误值
【发布时间】:2022-01-08 10:05:36
【问题描述】:

我正在编写一个可以读取以十六进制表示的整数的函数。

这是我的代码。不应修改main 函数。

#include <stdio.h>
#include <ctype.h>
#define SIZE 100

main()
{
    int array[SIZE], n;
    int gethex(int*);
    int i, sum;

    for (n = 0; n < SIZE && gethex(&array[n]) != EOF; n++)
        ;
    sum = 0;
    for (i = 0; i < n; i++)
        sum += array[i];
    
    printf("The sum is %d\n", sum);
}


int gethex(int *pn)
{
    int c, sign;

    c = getchar();
    while (isspace(c))
        ;

    if (!isxdigit(c) && c != EOF && c != '+' && c != '-') {
        ungetc(c, stdin); 
        return 0;
    }

    sign = (c == '-') ? -1 : 1;

    if (c == '+' || c == '-')
        c = getchar();

    for (*pn = 0; isxdigit (c); c = getchar()) {

        if (c >= '0' && c <= '9') {
            *pn = 16 * *pn + (c - '0');
        }

        else if (c >= 'a' && c <= 'f') {
            *pn = 16 * *pn + (c - 'a' + 10);
        }

        else if (c >= 'A' && c <= 'F') {
            *pn = 16 * *pn + (c - 'A' + 10);
        }
    }
    *pn *= sign;

    if (c == EOF) {
        *pn = c;
        return c;
    }
}

结果值应该是这样出来的。

-FFec
10000
^Z
The sum is 20

但是,我的代码输出

The sum is 1717986860

怎么了?

【问题讨论】:

  • while (isspace(c)) ; 将停止,因为没有任何改变。
  • "主函数不能修改。"嗯,它可以在你开发的时候。保持简单,只打印一个输入的结果。
  • main()从什么时候开始有效C?
  • @sej 我强烈建议您学习使用调试器,因为这将在您作为程序员的整个生命中很有价值,而不仅仅是这项任务。
  • @mkrieger1 我想它从 C 的黎明开始就有效。如果没有返回类型声明,则假定为 int。当然,现在这样写是非常规的。

标签: c input


【解决方案1】:

至少有这些问题:

警告未完全启用

警告没有完全启用,失去了 OP 和其他宝贵的时间。 @Jens

gethex() 的结尾缺少返回值。

警告:控制到达非空函数的结尾 [-Wreturn-type]

无限循环

一旦读取'\n,循环就永远不会结束。 @Weather Vane

while (isspace(c))
    ;

非十六进制输入也会与ungetc(c, stdin); 建立一个无限循环,因为相同的c 将在下一次函数调用时重复读取。

if (!isxdigit(c) && c != EOF && c != '+' && c != '-') {
    ungetc(c, stdin); 
    return 0;
}

int 可能溢出

*pn = 16 * *pn + (c - '0');*pn *= sign; 之类的代码会导致int 溢出,这是未定义的行为 (UB)。健壮的代码可以防止这种情况发生。


一些未经测试的代码来解决这些问题。

// Return 0 if non-numeric input detected.
// Return 2 when input out of int range
// Return 1 on success
// Return EOF when input is only white-space, sign or none
int gethex(int *pn) {
  int ch;

  // Consume leading white-space
  do {
    ch = getchar();
  } while (isspace(ch));

  // Get sign, if any
  int sign = ch;  // remember 1st
  if (ch == '-' || ch != '+') {
    ch = getchar();
  }

  if (ch == EOF) {
    return EOF;
  }

  if (!isxdigit(ch)) {
    // Consume non-numeric input
    return 0;  
    // Perhaps better to return EOF here to stop calling code.
  }

  int overflow = 0;
  int sum = 0;
  while (isxdigit(ch)) {
    int digit = 0;
    if (isdigit(ch)) {
      digit = ch - '0';
    } else if (isupper(ch)) {
      digit = ch - 'A' + 10;
    } else if (islower(ch)) {
      digit = ch - 'a' + 10;
    }
    if (sum <= INT_MIN / 16
        && (sum < INT_MIN / 16 || digit > -(INT_MIN % 16))) {
      overflow = 1;
      sum = INT_MIN;
    } else {
      // Accumulate as a negative number as there are more
      // negative vales than positive ones.  
      // This prevents bad code like -INT_MIN later. 
      sum = sum * 16 - digit;
    }
  }

  if (sign != '-') {
    if (sum < -INT_MAX) {
      overflow = 1;
      sum = INT_MAX;
    } else {
      sum = -sum;
    }
  }

  *pn = sum;
  ungetc(ch, stdin);
  return overflow ? 2 : 1;
}

【讨论】:

  • sej,嗯,当检测到非数字、非空白输入时,我建议返回 EOF 以停止 main() 中的循环。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-16
  • 2014-10-12
  • 2019-04-29
  • 1970-01-01
  • 1970-01-01
  • 2012-08-22
相关资源
最近更新 更多