【问题标题】:Why do multiple fgets require more than sizeof(type)为什么多个 fget 需要超过 sizeof(type)
【发布时间】:2020-04-20 12:18:36
【问题描述】:

我希望有人可以帮助我解释使用多个 fget 时的以下行为。

以下代码有效,用户需要为每个 fgets 输入一些内容:

char input[1]; // to store a character
fgets(input,3,stdin); // read a character from the keyboard

char test[5];// for second fgets
fgets(test,3,stdin); // to test if this asks for user input too

printf("The character input is %c",input[0]);

==========OUTPUT============
Enter a character please: 
e
f
The character input is e
=============================

但是,下面的代码只会让用户为 FIRST fgets 输入输入:

char input[1]; 
fgets(input,2,stdin); // THIS IS THE DIFFERENCE, USING 2 INSTEAD OF 3

char test[5];
fgets(test,3,stdin);

printf("The character input is %c",input[0]);
=====OUTPUT=============
Enter a character please: 
e
The character input is e
=========================

不同的是这一行:

fgets(input,2,stdin);

使用小于 3 表示以下 fget 不要求用户输入。 我认为这可能是因为在大小为 3 的情况下,当用户在输入字符后按 Enter 时,当大小为 3 或更大时,第一个 fgets 会消耗 \n。 但是,如果大小小于 3,则第一个 fget 不会使用 \n,而是将其留在标准输入上,因此它会被第二个 fget 使用,这就是为什么第二个 fget 无需等待用户输入就终止的原因。

如果我使用 sizeof(char) 作为那个值,那么我会得到输出:

=============OUTPUT============
Enter a character please: 
e
The character input is 
===============================

这很奇怪,因为我看到有人推荐使用 sizeof(type) 作为该参数。

我希望有人能解释为什么需要 3 来消耗 \n,我原以为 2 就足够了,例如1 个字节用于 char 和 1 个字节用于消耗 \n,如果是这种情况,那么推荐的 sizeof(type) 选择是错误的,因为您需要 sizeof(type)+1,但似乎您实际上需要sizeof(type) + 2 以允许使用 \n 并将其从标准输入中删除。请帮助我理解这一点,谢谢。

【问题讨论】:

  • 感谢您这么快回复。但是使用 char input[3] 我仍然有同样的问题,那就是 fgets(input,2,stdin);仍然会阻止以下 fgets 接受用户输入。如果我使用 char input[3] 和 fgets(input,sizeof(char),stdin) 然后输入 say 'e' 它根本不存储这是 input[0]。
  • 这就是为什么最好使用fgets(input, sizeof input, stdin); 你需要“1个字节用于char和1个字节来消耗\n”, 1终止空字符的字节。请使用足够大的缓冲区。
  • 字母、换行符、空字节。需要三个字节。在正常情况下,以char input[2048]; 开头——如果需要,您可以随时将其变大。您必须在一个小型系统上才能解决 2 KiB 的问题。
  • 感谢 Weather Vane 和 Jonathan Leffler,这听起来像是答案。这意味着必须使用 fgets(input,sizeof(char)+2,stdin);
  • 不,不要那样玩。首先分配一个大缓冲区。

标签: c input fgets


【解决方案1】:

你有两个不同的问题:

第一个是你写出你的数组input,这会导致未定义的行为

对于第二个问题,当您告诉 fgets 缓冲区的大小是 3 时,它将读取字符 换行符并将两者添加到您提供的缓冲区中并添加字符串空终止符。当您说大小为2 时,它将读取字符,但 换行,因为大小包括字符串空终止符。这意味着下一个fgets 调用将读取换行符并认为它是一个空行。

您可以通过使用一个足以容纳所有字符的缓冲区以及换行符和字符串空终止符来解决这些问题。对于单个字符,这意味着您的数组必须包含三个元素:

char input[3];
fgets(input, sizeof input, stdin);

作为可选解决方案,您可以读取单个字符(例如 getchargetc or fgetc)。

然后您需要在循环中读取(但不存储)字符,直到您读取换行符为止。

大概是这样的:

int input = getchar();

// Discard the rest of the line
for (int temp = getchar(); temp != '\n' && temp != EOF; temp = getchar())
{
    // Empty
}

【讨论】:

  • 谢谢你的回答,我想你已经总结了,从现在开始我会这样编码
  • 听从你的建议,我最终使用了这个:char c,d; while(d != '\n' && d != EOF){ c = d; d = fgetc(stdin); } printf("你输入了 %c\n",c);
  • @mertcoder 在循环条件中使用之前,您必须初始化d。未统一的变量将有一个不确定的(并且看似随机或垃圾)值。
  • @mertcoder 除了初始化d,您还必须将cd定义为int。将EOFchar 进行比较总是错误的。
  • @mertcoder 您的代码 sn-p 将打印 '\n' 或 EOF 之前的最后一个字符。这就是你想要的吗?
【解决方案2】:
char input[1]; // to store a character
fgets(input,3,stdin);  // read a character from the keyboard

输入变量, 如果用户输入像“new”这样的字符串,会导致分段错误, 当值超过 fgets(input,3,stdin) 的字符时 标准输入将忽略它们, 我实际上无法说明这个 fgets() 背后的设计与 char 数组具有相同的值。

【讨论】:

    猜你喜欢
    • 2020-08-27
    • 2015-07-18
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    • 2016-06-15
    • 1970-01-01
    相关资源
    最近更新 更多