【问题标题】:C getchar input problemsC getchar 输入问题
【发布时间】:2013-11-24 04:20:38
【问题描述】:

我需要接收单行字符并将它们从写入的基数转换为十进制基数,只要输入一个字符

我通过使用以下函数来做到这一点:

int inToDec(int base) //My assumption is that Enter will not be pressed as the first character - if it is, I am not sure what to do in that case
{
    int numdec=0, c;//decimalized number, a variable for character inpu
    while((c = getchar()) != '\n' && c != EOF)
    {
        if(c >= 97)//Checks if the char is an actual char
            c = c - 'a' - 1;
        else//or a digit char
            c = c;
        numdec += numdec * base + c;//every time another char is inputted, it multiplies the numdec by the base and adds the char's value in decimal base - which is essentially the algorithm for conversion to decimal base.
    }
    return numdec;
}

我的主要():

#include <stdio.h>
#include "funcs.h"

int main()
{
    int option, fbase, tbase, num1, num2;
    do
    {
        scanf("%d",&option);
        switch(option)
        {
        case 1:
            scanf("%d",&fbase);
            num1 = inToDec(fbase);
            num2 = inToDec(fbase);
            outFromDec(num1+num2,fbase);
            break;
        case 2:
            scanf("%d",&fbase);
            num1 = inToDec(fbase);
            num2 = inToDec(fbase);
            if(num1>=num2)
                outFromDec(num1-num2,fbase);
            else
                outFromDec(num2-num1,fbase);
            break;
        case 3:
            scanf("%d",&fbase);
            scanf("%d",&tbase);
            num1 = inToDec(fbase);
            outFromDec(num1,tbase);
            break;
        }
    }while(option != 4);
    return 0;
}

除了当我输入数字(在选项和所需的基数之后)并输入 Enter 继续下一个时,突然它开始一次又一次地打印一个字符而没有结束。我做错了什么,我该如何解决?或者,如果你不想向菜鸟解释一些明显的事实,我在哪里读到它(最好不要太多繁重的技术谈话,因为我对编程比较陌生)。

outFromDec() -

void outFromDec(int num, int base) //converts num into the base given and prints
{
    int count = 0 , temp = num, i;
    char c;
    while(temp != 0)
    {
        temp /= base;
        count++;
    }
    temp = num;
    do
    {
        for(i=1;i<count;i++)
            temp /= base;
        if(temp<=9)
            c = '0' + temp;
        else
            c = 'a' + temp - 1;
        putchar(c);
        count--;
        temp = num / temp;
    }while(temp != 0);
}

【问题讨论】:

  • 你没有打印任何东西,你在哪个平台上?
  • 平台?不明白你在问什么,但如果你指的是操作系统和软件,那么我在 Windows 7 上使用 Visual C++ 2010。
  • 我在询问操作系统。现在发布您的outFromDec 函数,它将帮助我们调试您的代码。 :)
  • 完成。顺便感谢您的帮助。

标签: c getchar


【解决方案1】:

这段代码有问题:

while(c = getchar() != '\n' && c != EOF)

没有足够的括号——赋值是一个低优先级的运算符。应该是:

while ((c = getchar()) != '\n' && c != EOF)

另一组问题是循环体中的转换代码:

    if (c >= 97)
        c = c - 'a' - 1;
    else
        c = c;
    numdec += numdec * base + c;

97 的选择大概是a 的 ASCII 或 ISO 8859-n 或 Unicode 代码点。这将忽略大写字母、标点符号,并将数字 09 视为 48..57。您可能需要使用#include &lt;ctype.h&gt;。它也不验证“数字”是否对基数有效。

但是,在第一次调用 intToDec() 时,读取的第一个字符是一个换行符,由 scanf() 留下,所以第一个数字始终为零,如果您按照提示每行输入一个数字到。

当您最终到达outToDec() 时,您会发现一些有趣的命理。我添加了printf() 语句来跟踪函数的进入和退出,以及循环中的关键点:

void outFromDec(int num, int base)
{
    printf("-->> %s: %d %d\n", __func__, num, base);
    int count = 0, temp = num, i;
    char c;
    while (temp != 0)
    {
        temp /= base;
        count++;
    }
    printf("Count: %d\n", count);
    temp = num;
    do
    {
        printf("count: %d; temp = %d\n", count, temp);
        for (i = 1; i < count; i++)
            temp /= base;
        if (temp <= 9)
            c = '0' + temp;
        else
            c = 'a' + temp - 1;
        putchar(c);
        count--;
        temp = num / temp;
    } while (temp != 0);
    printf("<<-- %s\n", __func__);
}

__func__ 是 C99 中包含函数名称的预定义标识符。您可能无法在 MSVC 中使用它;如果不是,请用函数名替换它。

对于输入199,程序的输出为:

-->> inToDec: 9
<<-- inToDec: 0
-->> inToDec: 9
<<-- inToDec: 57
-->> outFromDec: 57 9
Count: 2
count: 2; temp = 57
6count: 1; temp = 9
9count: 0; temp = 6
6count: -1; temp = 9
9count: -2; temp = 6

计数继续减少,6 和 9 继续交替。您似乎正在尝试使用首先发现的最高有效数字 (MSD) 来隔离数字。判断count的循环是正确的;循环打印数字显然不是。你应该可以从那里拿走它;是例行调试。请注意我如何使用打印语句来查看发生了什么。如果只看代码无法解决,如有必要,打印出每个表达式的结果。

我观察到以 10 为基数打印 57,您会发现要打印 2 个数字 (count == 2)。第一个数字将通过除以基数 (10) count-1 次得到;这会给你 5 打印。您可能需要从数字中减去 5 * 10,以便下一次(在本例中为最后一次)循环时,您只需从 7 开始,然后打印。循环将停止。如果count 变为负数,您应该确保循环中断。

这是一种格式化 10 位 32 位数字(甚至更适合 19 位 64 位数字)的昂贵方式。不过,它可以工作。标准程序以相反的顺序收集数字并安排以相反的顺序将它们打印出来。 (number % base 为您提供要打印的数字;number /= base 减少了要处理的位数。)


正如经常发生的那样,OP 受到人为约束,可能不使用字符串。呸!

这是一个看似稳健的“读取整数”函数。它确实假设了 2 的补码算法;它包含一个断言,如果它曾经在符号幅度或 1 的补码的机器上运行时应该触发(但我没有测试它;我没有任何此类机器可用于测试)。

请注意,代码将数字累加为负数,如果应该是正数,则在最后将其设为正数。这使得处理 INT_MIN 比尝试将其累积为正值int 更容易。

出于练习的目的,我将系统视为sizeof(intmax_t) == sizeof(int)(因此也是sizeof(int) == sizeof(long)sizeof(int) == sizeof(long long));如果整数类型是intmax_t 而不是int,则此技术将起作用。请注意,C 标准不排除这种假定的配置(但标准要求 CHAR_BIT * sizeof(int) &gt;= 64 是符合要求的实现)。

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

/* Read an integer from stdin without prompt: code is not allowed to use strings! */
enum { E_OK = 0, E_EOF = -1, E_INVCHAR = -2, E_OVERFLOW = -3 };

extern int read_an_int(int *value);

int read_an_int(int *value)
{
    int number = 0;
    int c;
    int pos_neg = +1;

    assert(-INT_MAX != INT_MIN);    // Probably 2's complement

    while ((c = getchar()) != EOF && isspace(c))
        ;
    if (c == '-')
    {
        pos_neg = -1;
        c = getchar();
    }
    else if (c == '+')
    {
        pos_neg = +1;
        c = getchar();
    }
    if (c == EOF)
        return E_EOF;
    if (!isdigit(c))
        return E_INVCHAR;

    number = '0' - c;   /* Negated digit */

    while ((c = getchar()) != EOF && isdigit(c))
    {
        int d = '0' - c; /* Negated digit */
        if (number < INT_MIN / 10 || (number == INT_MIN/10 && d < INT_MIN % 10))
            return E_OVERFLOW;
        //printf("N1 %d; d %d; ", number, d);
        number = number * 10 + d;
        //printf("N2 %d\n", number);
    }
    if (c != EOF)
        ungetc(c, stdin);

    if (pos_neg != -1)
    {
        //printf("Should be switched (%d)(%d)\n", pos_neg, number);
        if (number == INT_MIN)
            return E_OVERFLOW;
        number = -number;
        //printf("Should be positive (%d)(%d)\n", pos_neg, number);
    }

    *value = number;
    return E_OK;
}

static void gobble_input(void)
{
    int c;
    while ((c = getchar()) != EOF)
    {
        if (isdigit(c) || c == '+' || c == '-')
        {
            ungetc(c, stdin);
            break;
        }
        printf("Skip %c\n", c);
    }
}

int main(void)
{
    int rc;
    int number;

    while ((rc = read_an_int(&number)) != E_EOF)
    {
        switch (rc)
        {
        case E_INVCHAR:
            printf("Invalid character spotted\n");
            gobble_input();
            break;
        case E_OVERFLOW:
            printf("Input would have overflowed integer range %d..%d\n", INT_MIN, INT_MAX);
            break;
        case E_OK:
            printf("Input number: %d\n", number);
            break;
        default:
            assert(0);
            break;
        }
    }

    return 0;
}

我使用的测试数据文件是:

0
1
2
3
4
5
6
7
8
9
11
+123
1234
56789
+123456789
2147483647
2147483648
+000000123456789
000000123456789
-0000
+0000
-1
-2
-9
-21
-321
-4321
-2147483647
-2147483648
-2147483649
# Bogus data or partially bogus data
-
+
-213a
+213a
+.213
3.14159E+23

输出结果是:

Input number: 0
Input number: 1
Input number: 2
Input number: 3
Input number: 4
Input number: 5
Input number: 6
Input number: 7
Input number: 8
Input number: 9
Input number: 11
Input number: 123
Input number: 1234
Input number: 56789
Input number: 123456789
Input number: 2147483647
Input would have overflowed integer range -2147483648..2147483647
Input number: 123456789
Input number: 123456789
Input number: 0
Input number: 0
Input number: -1
Input number: -2
Input number: -9
Input number: -21
Input number: -321
Input number: -4321
Input number: -2147483647
Input number: -2147483648
Input would have overflowed integer range -2147483648..2147483647
Invalid character spotted
Skip  
Skip B
Skip o
Skip g
Skip u
Skip s
Skip  
Skip d
Skip a
Skip t
Skip a
Skip  
Skip o
Skip r
Skip  
Skip p
Skip a
Skip r
Skip t
Skip i
Skip a
Skip l
Skip l
Skip y
Skip  
Skip b
Skip o
Skip g
Skip u
Skip s
Skip  
Skip d
Skip a
Skip t
Skip a
Skip 

Invalid character spotted
Invalid character spotted
Input number: -213
Invalid character spotted
Skip 

Input number: 213
Invalid character spotted
Skip 

Invalid character spotted
Input number: 213
Input number: 3
Invalid character spotted
Input number: 14159
Invalid character spotted
Input number: 23

请注意,最后一行提供了 3 个有效数字(以及两个无效字符,.E)。

这不是特别容易;这就是为什么这些东西被编码在库函数中的原因。此外,“无字符串”要求意味着当存在无效字符或溢出时,我无法进行体面的错误报告。

【讨论】:

  • 在我发布这个之后我改变了它,因为我看到其他帖子这样做了。但是,是的,正如黑客所说,可悲的是,这不是原因。
  • 在我修复它之前,代码甚至没有为我成功编译(我使用非常严格的警告选项进行编译,-Werror 所以任何警告都被视为错误)。我现在重现了在单独的行上键入156 的问题(屏幕上满是5j 对)。我会进一步调试。如果你的编译器没有抱怨这个错误,你应该增加编译器警告,这样它就会这样做;如果还是不行,换个更好的编译器。
  • 一个完整的调试过程。不错。
  • 我希望我知道常规的调试程序……在哪里可以读到它们?如何处理输入问题?由于这也需要在 Unix 上运行,所以我不能真正使用 fflush(stdin)。
  • 在 SO 上查看答案,尤其是我的答案?我经常给出建议并添加调试代码等。(例如,来自today——“转储数据结构的功能”模因在我的调试建议中很常见。)对于输入问题,首先定义预期的输入。如果程序是交互式的,请给出提示——事实上,编写一个函数来提示和阅读。我经常使用fgets() 来读取完整的输入行,然后解析它,通常使用sscanf(),避免大多数换行问题。
【解决方案2】:

如果您在 Windows 中工作,请在 getchar() 所在的循环之前添加一个 fflush (stdin)。那就是:

int inToDec(int base) //My assumption is that Enter will not be pressed as the first character - if it is, I am not sure what to do in that case
{
    int numdec=0, c;//decimalized number, a variable for character inpu
    fflush (stdin);  /* flushes input buffer */
    while(c = getchar() != '\n' && c != EOF)
    {
        if(c >= 97)//Checks if the char is an actual char
            c = c - 'a' - 1;
        else//or a digit char
            c = c;
        numdec += numdec * base + c;//every time another char is inputted, it multiplies the numdec by the base and adds the char's value in decimal base - which is essentially the algorithm for conversion to decimal base.
    }
    return numdec;
}

【讨论】:

  • 如果不在 MS-DOS 上,fflush (stdin) 将导致 未定义的行为
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多