【问题标题】:How to prevent fgets() from picking \n as input? [duplicate]如何防止 fgets() 选择 \n 作为输入? [复制]
【发布时间】:2024-01-06 05:25:01
【问题描述】:

book_name 选择 \n 作为输入,并在新行中打印下一个变量。我插入此代码while ((getchar()) != '\n'); 以防止 fgets() 在使用 scanf() 后将 \n 作为输入。但我不明白为什么 fgets() 将 \n 作为输入。请解释一下。

代码

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

typedef struct {
    int id;
    char *book_name;
    char *author;
} book;

int main() {
    int n;

    printf("Enter number of books: \n");
    scanf("%d", &n);

    book *bk = calloc(n, sizeof(book));

    for (int i = 0; i < n; i++)
    {
        printf("Enter the no of the book: \n");
        scanf("%d", &((bk+i)->id));

        while ((getchar()) != '\n');

        (bk+i)->book_name = malloc(20);
        printf("Enter the name of the book: \n");
        fgets((bk+i)->book_name, 20, stdin);

        (bk+i)->author = malloc(20);
        printf("Enter the author of the book: \n");
        fgets((bk+i)->author, 20, stdin);
    }

    for (int i = 0; i < n; i++)
    {
        printf("%d %s %s\n", (bk+i)->id, (bk+i)->book_name, (bk+i)->author);
    }
    
    
    return 0;
}

输出

Output of code

【问题讨论】:

  • "为什么 fgets() 将 \n 作为输入。" --> 这就是fgets() 所做的。
  • 请注意,循环 while ((getchar()) != '\n'); 应该是 int c; while ((c = getchar()) != EOF &amp;&amp; c != '\n') ; — 如果您在读取换行符之前获得 EOF,您将在循环中花费很长时间(并且可能会发生!)。跨度>
  • 当有人输入诸如“灾难剖析”之类的标题(长度超过 18 个字符)时,您也会遇到问题。同样,如果“作者”是“威廉莎士比亚和弗朗西斯培根”,你就会遇到问题。您应该检查scanf()fgets() 调用是否也成功。 I/O 有一个可怕的习惯,就是不检查就会失败。

标签: c io scanf fgets


【解决方案1】:

查看回复帖子here

scanf() 将 '\n' 留在缓冲区中。因此,每当任何其他函数(例如 getchar() 或 fgets() 尝试从标准输入读取数据时,都会首先读取剩余的 '\n'。

如果您使用的是文件而不是标准输入,最好使用下面的代码以提高安全性。

FILE *fp = fopen("my_file.txt", "r");
int c;
while ((c = fgetc(fp)) != EOF && c != '\n');

你所做的是删除剩余\n的正确方法,@sadbro 可能误解了你的代码。

【讨论】:

  • 这个答案中有一些有用的建议,但没有得到很好的解释。第二段是准确的。只要输入来自stdin,代码 sn-p 就可以;如果它来自其他文件流fp,则需要int c; while ((c = getc(fp)) != EOF &amp;&amp; c != '\n') ;(我会将分号单独放在一行上,但这是风格——因为它符合K&R 的建议。)。问题中的代码在使用 fgets() 之前删除换行符接近正确 - 但它不检查 EOF。
  • 感谢您准确详细的解释。我已将代码更改为使用带有文件指针的 getc() 和使用字符变量。
  • 您应该注意我使用int 而不是char,因为getchar()getc()fgetc() 都返回int 而不是char。这是因为它们都返回任何可能的char 值和一个明显的负值EOF。您不能将所有这些都存储在 char 中。另请参阅while ((c = get(file)) != EOF) loop won't stop executing
  • 啊……确实。 EOF 本身表示为 -1。我会更加注意我的答案,以防止下次出现此类错误。谢谢。
  • @LazyRen 您应该使用 fgetc 而不是 getc 因为它已被 C 语言标准弃用