【问题标题】:code only take 2 inputs although it has 3 fgets代码虽然有 3 个 fget,但只需要 2 个输入
【发布时间】:2017-07-11 10:30:13
【问题描述】:
#include<string.h>
#include<stdio.h>
#include<stdlib.h>

int main(){
    int num;
    scanf("%d",&num);  // The input is 3 so i use it to simplify the question 
    char array[num][1000];
    fgets(array[0],1000,stdin);
    fgets(array[1],1000,stdin);
    fgets(array[2],1000,stdin);
    printf("%s %s %s",array[0],array[1],array[2]);
}

第一个输入,即 scanf 是 3 然后我输入圣雄和甘地。现在它应该为最后一个 fget 请求另一个输入,但程序结束打印圣雄甘地。但是我不使用 scanf 那么结果是正确的。如果可能,请提供代码。 P.S- 我是第一次使用 fgets,所以可能有一个非常基本的错误。

【问题讨论】:

  • @xing 我怀疑 printf 正在打印 \n。我该如何纠正它
  • @xing 你能提供一个代码吗

标签: c arrays scanf fgets


【解决方案1】:

正如 xing 在 cmets 中指出的那样,原因是 scanf() 在流中留下了一个换行符(由文件句柄 stdin 表示),它将由 fgets() 的第一次调用读取,导致它返回马上。

一般的解决方案是不要在同一个输入流上混合格式化输入(如scanf())和面向行的输入(如fgets()),因为它们会以意想不到的方式交互。您在此处的示例(scanf() 留下要读取的换行符,fgets() 由于遇到换行符而立即返回)是在同一流中混合输入样式的许多可能后果之一。

一种方法是使用fgets() 将数据读取到字符串中,然后使用sscanf() 从该字符串中读取int。与stdin 的交互则只使用fgets()

另一种选择是将fgets() 的所有用法更改为使用scanf()。这需要找到一种合理的格式(请记住,scanf() 在遇到空格时会停止读取某些内容 - 尽管有一些格式说明符会改变这一点)。

scanf() 格式字符串中添加空格的建议是有缺陷的。它适用于特定情况(例如这个),但不适用于其他情况。例如,如果您执行表单的循环

// assume variables declared as in the OP's question

while (some_condition_that_is_true_more_than_once())
{
    scanf("%d ",&num);
    fgets(array[0],1000,stdin);
    fgets(array[1],1000,stdin);
    fgets(array[2],1000,stdin);
}

由于循环中的最后一次调用 fgets() 与下一次迭代中的 scanf() 调用的交互,仍然存在潜在的交互(取决于用户输入的内容),从而产生意外结果。

【讨论】:

  • O_O 这就是你成为传奇的方式_/_
  • @peter 我如何在一行中打印 fgets 获得的所有名称,因为 fgets 还存储 \n 并因此使用 printf 全部打印在新行上。我怎样才能删除\n
  • 使用循环在字符串中查找换行符。用一些东西覆盖它。如果fgets() 读取的字符串有换行符,它将位于末尾(紧接在尾随零之前)。请记住,fgets() 可能会在读取换行符之前停止,因此不会将其放入字符串中。
【解决方案2】:

考虑对所有输入使用 fgets。根据需要使用 sscanf 或其他方法进行解析。
检查 fgets 和 sscanf 的返回,因为这表明存在问题。
do/while 循环将一直持续到处理完一个正整数。
包括澄清预期输入的提示。

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

int main(){
    char input[50] = "";
    int num = 0;
    int loop = 0;
    int valid = 0;

    do {
        printf ( "enter an integer\n");
        if ( fgets ( input, sizeof input, stdin)) {
            if ( 1 != ( valid = sscanf ( input, "%d", &num))) {// 1 means successful scan on an integer
                valid = 0;
                printf ( "try again to enter an integer\n");
            }
        }
        else {// fgets could not get input
            fprintf ( stderr, "problem with input\n");
            return 0;
        }
    } while ( !valid || num < 0);

    char array[num][1000];

    for ( loop = 0; loop < num; loop++) {
        printf ( "enter text for array[%d]\n", loop);
        if ( fgets(array[loop],sizeof array[loop], stdin)) {
            array[loop][strcspn( array[loop], "\n")] = '\0';// remove trailing newline if any
        }
        else {
            fprintf ( stderr, "problem with input\n");
            return 0;
        }
    }

    for ( loop = 0; loop < num; loop++) {
        printf("%s ", array[loop]);
    }
    printf("\n");
}

【讨论】:

    【解决方案3】:

    只需在scanf()中提供一个空格就可以了

    scanf("%d ",&amp;num);

    这将使调用fgets 三次(仅针对彼得指出的这种情况)。发生这种情况是因为当您在 STDIN 缓冲区中的 scanf() 存储 \n 之后按 ENTER 键并进入第一个 fgets() 调用。

    【讨论】:

    • 感谢 yaar,这样一个雄辩的解决方案。我如何在一行中打印 fgets 获得的所有名称,因为 fgets 还存储 \n 并因此使用 printf 所有都打印在新行上。
    • scanf("%d ",&amp;num); 不仅会消耗一个关注'\n',还会消耗所有关注的空格。如果以下 3 行中的第一行以空格开头,则这没有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2011-08-12
    • 1970-01-01
    相关资源
    最近更新 更多