【问题标题】:Issue with clearing buffer in C在 C 中清除缓冲区的问题
【发布时间】:2021-07-26 13:08:16
【问题描述】:

我正在尝试从键盘读取一些字符串并将它们保存到数组中。我指定了要读取的最大字符数并在中间首字母之后清除缓冲区以丢弃所有字符并超出限制。一旦我输入超过最大字符,一切似乎都很好。但是如果我输入的值小于最大值怎么办?我得到和额外的空行。似乎程序正在等待输入,我不知道为什么。有人能解释一下我知识的阴影吗?

这是我的代码 sn-p

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>


int main(void)
{
    char name[35];
    char middlename[7];
    char lastname[35];

    printf("Please enter name: ");
    scanf("%34[^\n]%*c", name);

    printf("Please enter middle name: ");
    scanf("%6[^\n]%*c", middlename);
    while (getchar() != '\n');

    printf("Please enter last name: ");
    scanf("%34[^\n]%*c", lastname);
}

这是我的输出:

Please enter name: Antony
Please enter middle name: Jr.
_ // here it waits for input

【问题讨论】:

  • 代码中while (getchar() != '\n');的作用是什么?
  • @ThomasJager 如果我不清除缓冲区并输入超过 6 个字符,则会显示不正确的输出跳过姓氏部分
  • 删除第二个 %*c 说明符并永远忘记它。在每次后续输入之前,使用 -while (getchar ()! = '\n' ); 清除缓冲区。

标签: c scanf buffer newline


【解决方案1】:

在每次这样的 scanf 调用中

scanf("%34[^\n]%*c", name);

删除第二个转换说明符

scanf("%34[^\n]", name);

用循环代替它

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

否则例如在这段代码中sn-p

scanf("%6[^\n]%*c", middlename);
while (getchar() != '\n');

您正在尝试读取换行符'\n' 两次。

另一种方法如下

printf("Please enter name: ");
scanf("%34[^\n]%*[^\n]", name);

printf("Please enter middle name: ");
scanf(" %6[^\n]%*[^\n]", middlename);

printf("Please enter last name: ");
scanf(" %34[^\n]*[^\n]", lastname);

注意第二次和第三次 scanf 调用中第一个格式说明符之前的空白。

【讨论】:

  • @WeatherVane 如果用户输入的字符多于预期,他想清除缓冲区。
  • 我看到之后:这是因为输入被截断 - 不是空格。如果只有换行符,则原始代码将等待不存在的输入。
【解决方案2】:

另一个函数可用于使用fgetc 获取输入。
只要有空间就填充数组。
读取并丢弃多余的字符。这会向用户报告。当要求用户重试时,可以丢弃整个输入。

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

int fgetcstr ( char *input, size_t size, FILE *fin) {
    int c = 0;
    int used = 0;
    int extra = 0;

    while( EOF != ( c = fgetc ( fin))) {//read until end of file
        if ( c == '\n') {
            break;//stop on newline
        }
        if ( used < size - ( size > 1)) {
            input[used] = c;//store character
            used++;//increment for next character
            if ( size > 1) {
                input[used] = 0;//zero terminate
            }
        }
        else {
            ++extra;
        }
    }
    if ( EOF == c && 0 == used) {//end of file and no characters read
        return EOF;
    }
    if ( extra) {
        printf ( "entered %d characters. only %zu allowed.\n\tExtra DISCARDED\n"
        , extra + used, size - ( size > 1));
        extra = 0;
        used = 0;
    }
    return 1;
}

int main ( void) {
    char name[35] = "";
    char middlename[7] = "";
    char lastname[35] = "";

    printf("Please enter name: ");
    fflush ( stdout);
    if ( EOF == fgetcstr ( name, sizeof name, stdin)) {
        fprintf ( stderr, "EOF\n");
        return 0;
    }
    printf("Please enter middle name: ");
    fflush ( stdout);
    if ( EOF == fgetcstr ( middlename, sizeof middlename, stdin)) {
        fprintf ( stderr, "EOF\n");
        return 0;
    }
    printf("Please enter last name: ");
    fflush ( stdout);
    if ( EOF == fgetcstr ( lastname, sizeof lastname, stdin)) {
        fprintf ( stderr, "EOF\n");
        return 0;
    }
    printf ( "name: %s\n", name);
    printf ( "middlename: %s\n", middlename);
    printf ( "lastname: %s\n", lastname);

    return 0;
}

【讨论】:

    【解决方案3】:

    一位同事在页面上方正确解释了所有内容。修饰符 ( * ) - 抑制下一个说明符的输入这一事实是一个好主意,但不适用于这种情况。您的代码与自身略有冲突。这样做,程序就会运行良好。

    #define _CRT_SECURE_NO_WARNINGS
    #include<stdio.h>
    
    int main(void)
    {
    char name[35];
    char middlename[7]; 
    char lastname[35];
    printf("Please enter name: "); 
    scanf(" %34[^\n]", name); 
    printf("Please enter middle name: "); 
    while (getchar() != '\n');
    scanf(" %6[^\n]", middlename);
    printf("Please enter last name: "); 
    while (getchar() != '\n');
    scanf(" %34[^\n]", lastname);
    while (getchar() != '\n');
     //Development of events
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-18
      • 2020-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多