fgets 之后获取键盘输入

发布于 2024-10-21 12:07:58 字数 1077 浏览 0 评论 0原文

我一生都无法平静地对待 C 字符串和输入/输出。

对于我的程序,我只需输入一个字符串,然后在以下代码中对其进行处理:(tmpstring 和 ch 已定义)

对于我的传入输入,我在终端中写入: echo "test" | ./program

    int main(int argc, char *argv[]) {
    char tmpstring[2048];
    int ch;
    int r;
    int c;

    fgets(tmpstring, sizeof tmpstring, stdin);
    while((ch = fgetc(stdin))!= EOF && ch != '\n');
    tmpstring[strlen(tmpstring)-1]='\0';

    strncpy(opponent, tmpstring+1, strlen(tmpstring+1));

    move();

move() 内部;

    char buffer[2048]={0};
    int r, c;
    r=0; c=0;
    printf("Your move (row column):");
    if((fgets(buffer, sizeof buffer, stdin)==NULL) || ((sscanf(buffer,"%d %d", &r, &c))!=2)){
            printf("Invalid input. Please insert two numbers separated by whitespace.\n");
            exit(1);
    }
    //continues

执行此操作会直接进入无效输入,而不要求更多输入。我已经阅读了有关如何不应该清除标准输入的所有内容(并且这是不可能的),但我真的不知道该怎么办。我显然试图用 while 循环的第二部分“转储”stdin。我已经改变了 &&在第一个条件之后到||在 while 循环中。没有变化。总的来说,在使用了 fgets 后如何请求更多输入?

*编辑:更多代码并分离原始 while 循环

I, for the life of me, cannot be at peace with c strings and input/output.

For my program I simply enter a string and it gets processed in the following code: (tmpstring and ch are already defined)

For my incomning input, I write in terminal: echo "test" | ./program

    int main(int argc, char *argv[]) {
    char tmpstring[2048];
    int ch;
    int r;
    int c;

    fgets(tmpstring, sizeof tmpstring, stdin);
    while((ch = fgetc(stdin))!= EOF && ch != '\n');
    tmpstring[strlen(tmpstring)-1]='\0';

    strncpy(opponent, tmpstring+1, strlen(tmpstring+1));

    move();

Inside of move();

    char buffer[2048]={0};
    int r, c;
    r=0; c=0;
    printf("Your move (row column):");
    if((fgets(buffer, sizeof buffer, stdin)==NULL) || ((sscanf(buffer,"%d %d", &r, &c))!=2)){
            printf("Invalid input. Please insert two numbers separated by whitespace.\n");
            exit(1);
    }
    //continues

Executing this goes straight into the invalid input without asking for more input. I've read all around about how you shouldn't clear stdin (and that it's impossible) but I really don't know what to do. I clearly tried to "dump" stdin with the second part of the while loop. I've changed the && after the first condition to an || in the while loop. No change. Overall, how can I ask for more input after already used fgets?

*edit: more code and separated the original while loop

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

铜锣湾横着走 2024-10-28 12:07:58

此类问题已在其他地方讨论过。
我将从这里复制我自己帖子的一部分:

Max使用 scanf 的字符串长度 -> ANSI C

  • 它通过调用 stdarg.h 库定义了一个具有可变数量参数的函数 my_scanf(),并结合 fgets() 和 vsscanf()。
  • 该函数旨在以正确的方式处理 fgets()sscanf() 的组合(实际上,我们必须使用 vsscanf()为了正确处理参数列表)。
  • 读取输入的字符数上限。如果输入超过此限制,则会被截断。 '\n' 已正确处理。该函数返回的值与 scanf() 的返回值相同。因此,您可以使用 my_scanf() 代替。

这里有代码:

#include <stdio.h>
#include <stdarg.h>

int my_scanf(const char* fmt, const unsigned int maxbuff, ...) {
    va_list ptr;
    int ret;

    if (maxbuff <= 0)
       return EOF; /* Bad size for buffer[] */

    char buffer[maxbuff+1];
    buffer[maxbuff-1] = '\0';  /* Quick buffer cleaning... */

    if (fgets(buffer, maxbuff+1, stdin) == NULL)
       return EOF; /* Error detected */
    else {
        if ((buffer[maxbuff-1] != '\n') && (buffer[maxbuff-1] != '\0'))
            /* Condition logically equivalent to:
                   fgets() has not reached an '\n'
            */
            while (getchar() != '\n')
               ; /* "Flushing" stdin... */

        va_start(ptr, maxbuff);
        ret = vsscanf(buffer, fmt, ptr);
        va_end(ptr);
        return ret;
    }    
}

#define MAXBUFF 20
int main(void) {
   int x; 
   float z;
   int scanf_ret = my_scanf("%d %g", MAXBUFF, &x, &z);
   printf("\nTest:\n x == %d\n z == %g\n scanfret == %d", x, z, scanf_ret);
   getchar();   
   return 0;   
}

函数 my_scanf() 具有原型

int my_scanf(const char* fmt, const int maxbuff, ...);
  • 它接受格式字符串 fmt,其行为方式与任何其他 scanf() 类似的行为相同。
  • 第二个参数是从标准输入(键盘)有效接受的最大字符数。
  • 返回值是一个int,如果maxbuff没有意义,或者发生了一些输入错误,则返回EOF。如果返回非负值,则与标准函数 sscanf()vsscanf() 返回的值相同。

    1. 在函数内部,maxbuff 以 1 递增,因为 fgets() 为额外的“\0”字符腾出了一些空间。
    2. maxbuff 的非正值将被立即丢弃。
    3. fgets() 将从 stdin(键盘)读取一个字符串,最多可容纳 maxbuff 个字符,包括“\n”。
    4. 如果用户输入了非常长的字符串,那么它将被截断,并且需要某种“刷新”机制,以便丢弃下一个“\n”之前的所有字符(ENTER)。如果不是,下一次键盘读取可能会出现较旧的字符,这根本不是我们所希望的。
      • “刷新”的条件是读取stdinfgets()尚未到达'\n'。
      • 当且仅当 buffer[maxbuff - 1] 不等于“\0”或“\n”时,此值为真。 (检查一下!

    5. 最后,采用 stdarg.h 和函数 vsscanf() 的适当(和标准)组合来处理变量参数列表。

This kind of problem has been discussed elsewhere.
I will copy a part of my own post, from here:

Max string length using scanf -> ANSI C

  • It is defined a function my_scanf() with variable number of parameters, by invoking the stdarg.h library, joint to a combination of fgets() and vsscanf().
  • That function is designed to handle in a right manner combinations of fgets() and sscanf() (actually, we have to use vsscanf() in order to properly process the list of arguments).
  • The input is read up to an upper limit of characters. if the input has more than this limit, it is truncated. The '\n' are handled correctly. The function returns the same value as scanf() would return. So, you can use my_scanf() instead.

Here you have the code:

#include <stdio.h>
#include <stdarg.h>

int my_scanf(const char* fmt, const unsigned int maxbuff, ...) {
    va_list ptr;
    int ret;

    if (maxbuff <= 0)
       return EOF; /* Bad size for buffer[] */

    char buffer[maxbuff+1];
    buffer[maxbuff-1] = '\0';  /* Quick buffer cleaning... */

    if (fgets(buffer, maxbuff+1, stdin) == NULL)
       return EOF; /* Error detected */
    else {
        if ((buffer[maxbuff-1] != '\n') && (buffer[maxbuff-1] != '\0'))
            /* Condition logically equivalent to:
                   fgets() has not reached an '\n'
            */
            while (getchar() != '\n')
               ; /* "Flushing" stdin... */

        va_start(ptr, maxbuff);
        ret = vsscanf(buffer, fmt, ptr);
        va_end(ptr);
        return ret;
    }    
}

#define MAXBUFF 20
int main(void) {
   int x; 
   float z;
   int scanf_ret = my_scanf("%d %g", MAXBUFF, &x, &z);
   printf("\nTest:\n x == %d\n z == %g\n scanfret == %d", x, z, scanf_ret);
   getchar();   
   return 0;   
}

The function my_scanf() has the prototype

int my_scanf(const char* fmt, const int maxbuff, ...);
  • It accepts a format string fmt that behaves in the same way as any other scanf()-like does.
  • The 2nd parameter is the maximum number of chars that will be effectively accepted from the standard input (keyboard).
  • The return value is an int, which is EOF if maxbuff has no sense, or well some input error happened. If a non-negative value is returned, it is the same that would be returned by the standard functions sscanf() or vsscanf().

    1. Inside the function, maxbuff is incremented in 1, because fgets() makes some room for an additional '\0' character.
    2. Non-positive values of maxbuff are immediatelly discarded.
    3. fgets() will read a string from stdin (keyboard) with room for at most maxbuff characters, including '\n'.
    4. If the user has entered a very long string, then it will be truncated, and some kind of "flush" mechanism is necessary in order to discard all the characters to the next '\n' (ENTER). If not, the next keyboard reading could have older characters, not desired at all.
      • The condition for "flushing" is that fgets() has not reached '\n' after reading stdin.
      • This is true if, and only if, buffer[maxbuff - 1] is not equal to '\0' nor '\n'. (Check it!)
    5. Finally, an appropiate (and standard) combination of stdarg.h macros and the function vsscanf() is employed to process the variable list of parameters.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文