如何使用fgets()而不会导致错误,并在输出的同一行中包含'.?

How to use fgets() without resulting in bug and also include '.' in the same line of the output?

提问人:Greeshma 提问时间:10/26/2023 最后编辑:Greeshma 更新时间:10/26/2023 访问量:57

问:

我正在学习和练习“C”。使用 fgets() 函数对我来说是一个挑战。例如,下面的代码运行绝对正常。当我运行这段代码时,它采用我妈妈的名字(firstName lastName)作为输入,但“.”被放在下一行。如何获取输出同一行的周期?

#include <stdio.h>

int main() 
{
    char motherName[30];
    printf("Enter your mother's full name: ");
    fgets(motherName, sizeof(motherName), stdin);
    printf("Your mom's full name is %s.", motherName);
    
    return 0;
}

还有另一个查询。当将 fgets() 函数与其他变量输入一起使用时,它会导致一个错误。前两个输入被正确接收,输出完全是我想要的方式。但是当涉及到 fgets() 时,它不接受任何输入。我希望你能帮我解决这个问题。我也是stack overflow的新手,谢谢你的帮助!

#include <stdio.h>

int main()
{
    int num;
    printf("What's your favorite number: ");
    scanf("%d", &num);
    printf("Your favorite number is %d.\n", num);

    char name[20];
    printf("Enter your name: ");
    scanf("%s", name);
    printf("Your name is %s.\n", name);

    char motherName[30];
    printf("Enter your mother's full name: ");
    fgets(motherName, sizeof(motherName), stdin);
    printf("%s is your mom's full name.", motherName);

    return 0;
}
C 输入 scanf fgets

评论

0赞 chux - Reinstate Monica 10/26/2023
fgets()之后导致麻烦。请勿使用 .谁建议的?scanf("%s", name);scanf()scanf()
0赞 sinsedrix 10/26/2023
似乎carrige返回已添加到您的输入中。你试过修剪它吗?

答:

2赞 Fe2O3 10/26/2023 #1

根据文档,填充缓冲区,包括终止 LF(换行符)字符。fgets()

要在以下位置处理换行符(换行符):fgets()

#include <string.h> // add this header to use MANY string functions
/* ... */
    fgets(motherName, sizeof motherName, stdin); // "()" unnecessary with sizeof in this usage.
    motherName[ strcspn(motherName, "\n") ] = '\0'; // add this line to obliterate LF

至于第二个问题,这是一场摔跤比赛,既要同时使用,又要一起使用。前者将在缓冲区中留下(意外的)空格(包括 LF)。而且,正如你所做的那样,大多数代码不会检查是否分配了所有预期的值。scanf()fgets()scanf()

现在您正在使用 ,停止使用 for input。标准库包含将字符串分隔为标记 () 并将这些标记转换为 () 或 () 所需的所有函数。这就是大男孩的做法。fgets()scanf()strtok()intstrtol()doublestrtod()


离开键盘,了解标准库提供的功能。


编辑
修改后的代码:

#include <stdio.h>
#include <string.h> // Added

int main()
{
    char motherName[30];
    printf("Enter your mother's full name: ");
    fgets(motherName, sizeof(motherName), stdin);

    motherName[ strcspn(motherName, "\n") ] = '\0'; // obliterate LF

    printf("Your mom's full name is %s.\n", motherName); // added LF to this output

    return 0;
}

结果:

Enter your mother's full name: She who cooks dinner
Your mom's full name is She who cooks dinner.

第二个问题:

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

int main()
{
    char buf[ 128 ]; // some size big enough

    printf("What's your favorite number: ");
    fgets( buf, sizeof buf, stdin );

    int num = strtol( buf, NULL, 10 ); // new function. read doco
    printf("Your favorite number is %d.\n", num);

    printf("Enter your name: ");
    fgets( buf, sizeof buf, stdin );
    buf[ strcspn(buf, "\n") ] = '\0'; // << NB
    printf("Your name is %s.\n", buf);

    printf("Enter your mother's full name: ");
    fgets( buf, sizeof buf, stdin );
    buf[ strcspn(buf, "\n") ] = '\0'; // << NB
    printf("%s is your mom's full name.\n", buf);

    return 0;
}

结果:

What's your favorite number: 27
Your favorite number is 27.
Enter your name: fe2O3
Your name is fe2O3.
Enter your mother's full name: Marge Simpson
Marge Simpson is your mom's full name.

不能说你为什么有问题......

评论

0赞 Greeshma 10/26/2023
我尝试了你的建议,它给了我一个错误。你能把整个代码发送出去进一步澄清吗?
0赞 Fe2O3 10/26/2023
错字。。。我在那一行上输入了撇号而不是双引号......哎呀。。。再次尝试复制/粘贴...或者如果不是这样,请确切地说明错误是什么。您发布的哪个代码片段给您带来了错误?
0赞 Greeshma 10/26/2023
main.c:9:37:警告:传递“strcspn”的参数 2 在没有强制转换的情况下从整数生成指针 [-Wint-conversion] 9 |母亲名[ strcspn(母亲名, '\n') ] = '\0'; |^~~~ | | |int
0赞 Fe2O3 10/26/2023
我已经在之前的评论中承认了我的错别字......使用双引号,而不是单引号。更改为'\n'"\n"
0赞 Greeshma 10/26/2023
试着完全按照你说的去做,它向我展示了一堆错误。无法在此处发布,它超出了此处允许的字符。
0赞 HolderRoberts 10/26/2023 #2

顶级域名

你可以改变

fgets(motherName, sizeof(motherName), stdin);

scanf("%[^n]", motherName);

解释

使用像 或这样的 char-input 函数的 format-input 函数会导致一些令人困惑的结果,因为不会消耗尾随的 .scanfgetcharfgetsscanf\n

假设你只写一个简单的代码来阅读一个单词和一行:

#include <stdio.h>
int main() {
  char word[32];
  char line[32];
  scanf("%s", word);
  fgets(line, 31, stdin);
  return 0;
}

然后你输入

hey
hello world

然后 scanf 会读取并将其存储到数组中并留下 '\n',为此只需读取此内容并认为“哦,这是一个空行,我只是遇到它的结尾”。Fianlly,是和是.heywordfgets\nwordheyline\n

但是如何解决呢?您可以读取所有行并手动处理它们,也可以使用上述信息解决此问题。例如,只需再使用一个来读取尾随,如下所示:fgetsfgets\n

#include <stdio.h>
int main() {
  char word[32];
  char line[32];
  scanf("%s", word);
  fgets(line, 31, stdin);  // it will consume the '\n'
  fgets(line, 31, stdin);
  return 0;
}

使用上面相同的输入,它会导致结果 where is 和 is 。wordheylinehello world\n

但是,我们仍然会遇到两个问题:

  1. 使用另一个真的很丑.fgets
  2. fgets读取预期的尾随。\n

如果你想优雅地修复它们,我会介绍另一个技巧:否定扫描集。您可以在 https://cplusplus.com/reference/cstdio/scanf/ 获取详细信息参考

您可以选择,因为 scanf with 将在遇到任何空间时停止,但您可以使用否定扫描集来防止结束读取,除非满足 .我只是在这里展示用法:fgets%sscanf\n

#include <stdio.h>
int main() {
  char word[32];
  char line[32];
  scanf("%s", word);
  scanf("%[^\n]", line); // The reading only stops once meeting "\n" or EOF
  return 0;
}

使用上面相同的输入,将是 和 将是 .wordheylinehello world

评论

1赞 Fe2O3 10/26/2023
从您的示例中可以清楚地看出,用户必须了解缓冲区大小,而用户也可能使用 ...黑客的爱......fgets()scanf()gets()scanf()
0赞 Serge Ballesta 10/26/2023
更明确地说,可以很容易地给出可以通过简单的缓冲区溢出中断的代码。这是可以避免的,因为可以限制输入宽度(而丑陋的则不存在解决方案),但正确使用要求用户非常谨慎。换句话说,建议在不指定必要的预防措施(测试返回值并防止任何缓冲区溢出)的情况下使用是不好的。scanfgetsscanfscanf