输入无效条目时清除scanf缓冲区的好方法 [英] Good way to flush scanf buffer when invalid entry entered

查看:249
本文介绍了输入无效条目时清除scanf缓冲区的好方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在想办法在 scanf 函数中刷新错误的条目,以允许循环提示完成他们的工作。

我在这里有一个函数调用来刷新输入。这可以工作,但如果我在输入 2q 之类的东西时请求一个 int ,它仍然有问题。

  void flushKeyBoard()
{
int ch; ((ch = getc(stdin))!= EOF&& ch!!='\\\
'); //变量将数据读入
;
}

然后我会在另一个函数中使用类似这样的函数:

  printf(Enter a value:); 
check = scanf(%f,& b);

while(check == 0)
{
printf(输入的数字无效,请重新输入:);
check = scanf(%f,& b);
flushKeyBoard();
}

有什么更好的想法?有人建议fflush();但在这里使用它并不是真正的标准。

解决方案

使用 getchar (普通,易于理解)



  int c; ((c = getchar())!= EOF&& c!='\\\
');

; / *<请注意分号! * /

if(c == EOF){
if(feof(stdin)){
/ *处理stdin EOF。 * /
}
else {
/ *处理stdin错误。 * /
}
}






< h1>使用 fgets (少见,不易理解)

  char buf [8]; 

while(fgets(buf,sizeof buf,stdin)!= NULL){
size_t len = strlen(buf);
$ b $ * / $
*如果在'\ n'之前遇到EOF,则退出循环,如果检测到'\ n',则退出循环
*。
* /
if(len + 1!= sizeof(buf)|| memchr(buf,'\\\
',len))
break;
}

if(feof(stdin)){
/ *处理stdin EOF。 * /
}
else {
/ *处理stdin错误。 * /
}






使用扫描集 scanf (可能不常见,易于理解)



  / * 
*将扫描集与分配抑制组合(
* scanset之前的'*')将在EOF / error上返回EOF,如果读取了'\ n',则返回0。 $($)$ b $ /
if(scanf(%* [^ \\\
])== EOF){
if(feof(stdin)){
// Handle stdin EOF。
}
else {
//处理stdin错误。
}
}
getchar(); //刷新'\\\
'。






使用 getline (可能不常见,很难)



  char * buf = NULL; 
size_t bufsize = 0;
ssize_t len;

/ * getline()将停止阅读'\\\
'或EOF。 * /
len = getline(& buf,& bufsize,stdin);

/ *没有字节读取和EOF遇到,或者出现错误。 * /
if(len == -1){
if(feof(stdin)){
/ *处理stdin EOF。 * /
}
else if(ferror(stdin)){
/ *处理stdin错误。 * /
}
else {
/ *如果需要,处理errno错误。 * /
}
/ *
*buf的值在这里是不确定的,所以您可能
*只是想从此处的函数/程序返回
*而不是继续并可能释放无效的
*缓冲区。
* /
}
free(buf);






当然,所有这些方法都假设您想要以与 \\\
不同的方式处理发生在EOF /错误上的事情,甚至所有这三个事件都是单独的情况。例如,通过将上面的代码片段放到一个自包含的函数中,如果 \\\
0
>已阅读或 EOF 在EOF /错误,甚至 0 \\\
EOF 在EOF上, 1 出错。



值得注意的是:


  • getchar fgets 方法是100%跨平台的。我比较喜欢 getchar 方法。

  • scanset方法不是跨平台的,因为并不是所有的编译器都实现了扫描集因此不符合C99标准)。
  • getline 方法也不是跨平台的:它主要在GNU / Linux上实现和其他一些POSIX操作系统上;这个时候不包括Windows。一旦你有一定的管理内存和处理指针的经验,写一个自己并不难,但是从编写 getline 的实现之后,最好使用前两种方法之一, code>可能最终会使用 fgetc fgets 无论如何( fgetc(stdin ) getchar()应该具有相同的行为)。


I have been thinking of ways to flush bad entries in scanf functions to allow for loop prompts to do their job.

I have a function call here that flushes the input. This works but it's still buggy if I enter something like 2q when I ask for an int.

void flushKeyBoard()
{
    int ch; //variable to read data into
    while((ch = getc(stdin)) != EOF && ch != '\n');
}

And then I'll have something like this in another function:

printf("Enter a value: ");
check = scanf("%f", &b);

while(check == 0)
{
    printf("Invalid number entered. Please re-enter: ");
    check = scanf("%f, &b");
    flushKeyBoard();
}

Any better ideas? Someone suggested fflush(); but it's not really standard to use that here..

解决方案

Using getchar (common, easily comprehensible)

int c;

while ((c = getchar()) != EOF && c != '\n'); /* <note the semicolon! */

if (c == EOF) {
    if (feof(stdin)) {
        /* Handle stdin EOF. */
    }
    else {
        /* Handle stdin error. */
    }
}


Using fgets (less common, less comprehensible)

char buf[8];

while (fgets(buf, sizeof buf, stdin) != NULL) {
    size_t len = strlen(buf);

    /*
     * Exit the loop if either EOF was encountered before '\n', or
     * if '\n' is detected.
     */
    if (len + 1 != sizeof(buf) || memchr(buf, '\n', len))
        break;
}

if (feof(stdin)) {
    /* Handle stdin EOF. */
}
else {
    /* Handle stdin error. */
}


Using a scanset with scanf (likely uncommon, easily comprehensible)

/*
 * Combining the scanset with assignment suppression (the '*' before the
 * scanset) will return EOF on EOF/error and 0 if '\n' was read.
 */
if (scanf("%*[^\n]") == EOF) {
    if (feof(stdin)) {
        // Handle stdin EOF.
    }
    else {
        // Handle stdin error.
    }
}
getchar(); // Flush the '\n'.


Using getline (likely uncommon, difficult)

char *buf = NULL;
size_t bufsize = 0;
ssize_t len;

/* getline() will stop reading on '\n' or EOF. */
len = getline(&buf, &bufsize, stdin);

/* No bytes read and EOF encountered, or there was an error. */
if (len == -1) {
    if (feof(stdin)) {
        /* Handle stdin EOF. */
    }
    else if (ferror(stdin)) {
        /* Handle stdin error. */
    }
    else {
        /* Handle errno error, if desired. */
    }
    /*
     * The value of "buf" is indeterminate here, so you likely
     * just want to return from the function/program at this point
     * rather than continuing and potentially freeing an invalid
     * buffer.
     */
}
free(buf);


Of course, all of these methods assume you want to handle things that happen on EOF/error differently than with \n, perhaps even all three being separate cases. For example, by placing one of the above snippets into a self-contained function, you might return 0 if \n was read or EOF on EOF/error, or even 0 on \n, EOF on EOF, and 1 on error.

Things worth noting:

  • The getchar and fgets methods are 100% cross-platform. I prefer the getchar method for its simplicity.
  • The scanset method is less cross-platform only because not all compilers implement scansets (and are therefore not C99-compliant).
  • The getline method is also not quite cross-platform: it's primarily implemented on GNU/Linux and on some other POSIX operating systems; this does not include Windows at this time. It isn't terribly difficult to write one yourself once you have some experience managing memory and working with pointers, but you'd be better off using one of the first two methods since writing an implementation of getline would likely end up using fgetc or fgets anyway (fgetc(stdin) and getchar() should behave identically).

这篇关于输入无效条目时清除scanf缓冲区的好方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆