【问题标题】:C Getting decimal input from user issueC从用户问题中获取十进制输入
【发布时间】:2016-01-17 00:51:12
【问题描述】:

我正在尝试编写一个函数来从用户那里获取十进制输入并返回从 ASCII 转换而来的实际值。但是,该函数会导致跳过用户的下一个输入。如:
输入输入:123

输入输入:/* 不;允许输入 */

输入输入:456

long sum = 0;

int character = fgetc(stdin);

while(character != '\n'){

    if(character >= '0' && character <= '9'){
        /* convert from ASCII */
        character -= '0';
        sum = sum * 10 + character;

    }
    else{
        /* reenter number */
    }
    character = fgetc(stdin);
}
return sum;

【问题讨论】:

  • 使用&lt;ctype.h&gt;isdigit();考虑换行符;考虑EOF。最好使用int 作为fgetc() 返回的值。如果您显示正在使用的sum,或者根本不显示sum,那就更好了。实际上,一个完整的功能会更好。请尽快阅读About 页面,了解如何创建 MCVE (How to create a Minimal, Complete, and Verifiable Example?)。
  • 这不是转载。
  • 我似乎在标准输入缓冲区中有一个额外的换行符。有什么理由吗?
  • 空的else 子句有什么内容吗?如果没有,请将其删除。它正式并没有造成任何伤害,但它看起来很傻 - 好像有人打算写点东西但忘记回来完成它。

标签: c


【解决方案1】:

要弄清楚为什么您的代码不起作用,我建议您发布您的完整代码,因为问题可能在于您调用此函数的方式。

所以在发布完整代码之前,我只能告诉你这段代码在我的机器上运行良好:

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

int getlong();

int main() {
    printf("\t%d\n", getlong());
    printf("\t%d\n", getlong());
    return 0;
}

int getlong() {
    long sum = 0;
    int character = fgetc(stdin);
    while (character != '\n') {
        if (isdigit(character)) {
            /* convert from ASCII */
            character -= '0';
            sum = sum * 10 + character;
            character = fgetc(stdin);
        }
        else {
            character = fgetc(stdin);
            continue;
        }
    }
    return sum;
}

包含ctype.h是为了使用isdigit(),同时告诉你一个字符是否是十进制数字。

但实际上,您不必自己做所有事情。使用标准库对您和计算机都更加有效和高效。

例如可以直接从stdin扫描一个长整数:

#include <stdio.h>

int main() {
    long value;
    puts("Please input numbers:");
    while (scanf(" %ld", &value) != 1) {
        puts("Only numbers are welcome:");
        scanf("%*[^\n]");
    }
    printf("%ld", value);
    return 0;
}

注意format 开头的空白,这使得scanf() 丢弃所有提取的空白字符(包括空格、换行符和制表符),直到遇到非空白字符。

或者,使用strtol(),虽然比较少见:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char buf[80];
    char *pEnd;
    long value;
    do
    {
        puts("Numbers please:");
        if (fgets(buf, 80, stdin) == NULL)
        {
            perror("fgets()");
            return 1;
        }
        value = strtol(buf, &pEnd, 10);
    }
    while (*pEnd != '\n');
    printf("%ld", value);
    return 0;
}

当然sscanf()也可以,你自己写代码就行了。

【讨论】:

    【解决方案2】:

    来自 cmets:
    标准输入缓冲区中的一个额外换行符...
    尝试使用以下格式字符串将您当前的方法替换为scanf()

    char* fmt = "%[^\n]%*c";
    

    它将所有内容读取到换行符,然后使用换行符。 * 是一个赋值抑制器

    示例:(包括将输入字符串转换为浮点数/整数的函数)

    float get_float(void);
    long get_int(void);
    int main(void)
    {
    
        float num_f = get_float();
        long num_i = get_int();
    
        return 0;
    }
    
    float get_float(void)
    {
        char input[80];
        char **dummy={0};
        char* fmt = "%[^\n]%*c";
        printf("Enter floating point number and hit return:\n");
        scanf(fmt, input);
        return strtod(input, dummy);
    }
    
    long get_int(void)
    {
        char input[80];
        char **dummy={0};
        char* fmt = "%[^\n]%*c";
        printf("Enter integer number and hit return:\n");
        scanf(fmt, input);
        return strtol(input, dummy, 10);
    }
    

    注意:这些函数只是简单的说明如何将输入转换为数字变量,并且在编写时没有任何错误或范围检查。正如评论者所说,在实施生产版本之前详细阅读 strtol()strtof 是值得的。 (链接指向 Linux 手册页,但因为这两个函数都是 C 标准库的一部分,所以文档也可以在 MSDN here@ 987654324@)

    【讨论】:

    • 这是一个好方法。提到验证返回可能会有所帮助,OP 需要检查 errnoERANGE 以及返回 LONG_MINLONG_MAX 以防止上溢/下溢,还需要检查 ptr 和 @987654334 @(man strtol 中的参数)来验证是否进行了转换。
    • @DavidC.Rankin - 谢谢。你的评论太完整了,我差点直接复制粘贴了。
    【解决方案3】:

    为什么不直接使用fgetssscanf

    char buf[80];
    float n;
    
    if (fgets(buf, 80, stdin) != NULL) {        
        if (sscanf(buf, "%f", &n) == 1)
            printf("%f\n", n);
        else
            fprintf(stderr, "invalid float\n");
    }
    

    【讨论】:

    • 看起来输入是一个十进制整数,因此使用long 表示sum,也许更适合命名为value。但是使用fgets()sscanf() 是一种很好的技术,尽管在使用sscanf() 输入之前确实需要测试fgets() 的返回值,如果输入字符串为空,sscanf() 将返回 EOF,或者仅包含空格(例如,仅包含换行符),因此测试应该是 == 1 而不是您使用的隐式 != 0
    猜你喜欢
    • 2013-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-20
    相关资源
    最近更新 更多