开发者

Getting keyboard input after fgets

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


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.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜