【问题标题】:Is there an elegant way to handle the '\n' that gets read by input functions (getchar(), fgets(), scanf()) in C?是否有一种优雅的方式来处理 C 中的输入函数(getchar()、fgets()、scanf())读取的“\n”?
【发布时间】:2022-06-16 18:26:20
【问题描述】:

我正在尝试 K&R 的一个简单练习,使用指针将 string2 附加到 string1 的末尾。如果发生溢出,即 string1 的缓冲区不能包含所有 string2 我想提示用户重新输入 string2 或退出。

我写了以下代码:

#include<stdio.h>
#include<string.h>
#define MAXLINE 1000
int get_input(char *s);
int str_cat(char *s, char *t);

void main()
{
    char input1[MAXLINE], input2[MAXLINE], c; 
    get_input(input1);
    check:
    get_input(input2);
    if((strlen(input1) + strlen(input2) + 2) <= MAXLINE)
    {
        str_cat(input1, input2);
        printf("%s\n", input1);
    
    }
    else
    {
        input2[0] = '\0';
        printf("String overflow\n Press: \n 1: Re-enter string. \n 2: Exit.\n");
        scanf(" %d", &c);
        if(c == 1){
            input2[0] = '\0';
            get_input(input2);
            goto check;
        }

    }

}

int get_input(char *arr)
{
    int c;
    printf("Enter the string: \n");
    while(fgets(arr, MAXLINE, stdin))
    {
        break;
    }
}
int str_cat(char *s, char *t)
{
    while(*s != '\0')
    {
        s++;
    }
    while((*s++ = *t++) != '\0')
    {
        ;
    }
    *s = '\0';
}

最初,我使用书中提到的标准getchar() 函数来读取get_input() 中的输入,如下所示:

int get_input(char *arr)
{
    int c;
    printf("Enter the string: \n");
    while((c = getchar()) != '\n' && c != EOF)
    {
        *arr++ = c;
    }
    *arr = '\0';
}
  • 我是新手,我阅读了this 并理解了我的错误。我知道不应该使用不同的输入函数来读取标准输入,'\n' 留在输入流中,由getchar() 选择导致我的条件失败。

  • 所以,我决定使用fgets() 来读取输入并修改scanf("%d", &amp;c),如scanf(" %d", c) 线程中提到的那样。这确实有效(有点),但会导致我不想要的行为。

所以,我有几个问题:

  1. 在遇到'\n' 时读取输入以获取fgets() 的更好方法是什么?

     while(fgets(arr, MAXLINE, stdin))
     {
         break;
     }
    
  2. fgets() 在遇到'\n' or EOF 时停止读取该行并将其存储为输入。但是,它最终将'\n' 存储在字符串的末尾。有没有办法防止这种情况发生,还是我必须手动覆盖'\n'

  3. 即使我使用了 scanf(" %d", &amp;c) 的修改版本,我的输出看起来像 这个:(https://imgur.com/a/RaC2Kc6)。尽管如此,当出现溢出情况时提示重新输入第二个字符串时,我得到了两次Enter the string: 。修改后的scanf() 是否影响了我的输入?我该如何纠正?

【问题讨论】:

  • 您不需要在scanf(" %d", &amp;c) 中添加空格,因为说明符%d%f%s(及其变体)会自动过滤前导空格。您确实需要%c%[...]%n 的空格,否则它们会读取每个字符。了解不同格式如何处理空格是避免令人讨厌的问题的关键。
  • fgets 保留的换行符(如果缓冲区中有空间)请参阅Removing trailing newline character from fgets() input 以获取防弹单行。
  • 欢迎来到 StackOverflow。我注意到您为使您的第一个问题写得很好而付出了很多努力,我只想感谢您。
  • 如果您可能需要拒绝输入(或者用户可能会输入垃圾),请不要使用scanf,使用fgets 输入字符串并使用@987654353 解析它@ 或其他。如果您需要拒绝输入,这比scanf 可能会被垃圾阻塞的缓冲区简单得多:您只需输入另一个字符串。

标签: c scanf stdin fgets getchar


【解决方案1】:

一般情况下,不要将fgetsscanf 混用。虽然它可能有点臃肿,但通过与fgets 读取输入保持一致,然后使用sscanf 解析它,您将避免很多问题。 (注意多余的 s)

删除换行符的好方法是buffer[strcspn(buffer, "\n")] = 0

例子:

// Read line and handle error if it occurs
if(!fgets(buffer, buffersize, stdin)) {
    // Handle error
}

// Remove newline (if you want, not necessarily something you need)
buffer[strcspn(buffer, "\n")] = 0;

// Parse and handle error
int val;
if(sscanf(buffer, "%d", &val) != 1) {
    // Handle error
}

// Now you can use the variable val

这里有一件事在某些情况下可能很危险,那就是如果buffer 不够大,无法容纳完整的行。 fgets 不会读取超过 buffersize 个字符。如果该行较长,则剩余部分将留在标准输入中。

【讨论】:

    猜你喜欢
    • 2014-02-10
    • 2015-07-10
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    • 1970-01-01
    • 1970-01-01
    • 2022-06-11
    相关资源
    最近更新 更多