Get scanf to quit when it reads a newline?

后端 未结 5 1422
轻奢々
轻奢々 2020-11-30 09:27

If I input 5 5 at the terminal, press enter, and press enter again, I want to exit out of the loop.

int readCoefficents(double complex *c){
             


        
相关标签:
5条回答
  • 2020-11-30 09:56

    re PAXDIABLO solution: it does not work properly with EMPTY line entered by user, so this line shall be added in your getLine() function

    if (strlen(buff) <= 1) return NO_INPUT;
    

    after the line:

    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;
    

    So it will become :

    ...
       if (strlen(buff) <= 1) return NO_INPUT;
       if (fgets (buff, sz, stdin) == NULL) return NO_INPUT;
    ....
    
    0 讨论(0)
  • 2020-11-30 09:58

    The specific problem you're having is that a scanf format string of %f will skip white space (including newlines) until it finds an actual character to scan. From the c99 standard:

    A conversion specification is executed in the following steps:
       -   Input white-space characters (as specified by the isspace function) are skipped, unless the specification includes a '[', 'c', or 'n' specifier.

    and, elsewhere, describing isspace():

    The standard white-space characters are the following: space ' ', form feed '\f', new-line '\n', carriage return '\r', horizontal tab '\t', and vertical tab '\v'.

    Your best bet is to use fgets to get the line (and this can be protected from buffer overflow very easily), then use sscanf on the resultant line.

    The scanf function is one of those ones you should look at very warily. The following piece of code is one I often use to handle line input:

    #include <stdio.h>
    #include <string.h>
    
    #define OK       0
    #define NO_INPUT 1
    #define TOO_LONG 2
    static int getLine (char *prmpt, char *buff, size_t sz) {
        int ch, extra;
    
        // Get line with buffer overrun protection.
        if (prmpt != NULL) {
            printf ("%s", prmpt);
            fflush (stdout);
        }
        if (fgets (buff, sz, stdin) == NULL)
            return NO_INPUT;
    
        // If it was too long, there'll be no newline. In that case, we flush
        // to end of line so that excess doesn't affect the next call.
        if (buff[strlen(buff)-1] != '\n') {
            extra = 0;
            while (((ch = getchar()) != '\n') && (ch != EOF))
                extra = 1;
            return (extra == 1) ? TOO_LONG : OK;
        }
    
        // Otherwise remove newline and give string back to caller.
        buff[strlen(buff)-1] = '\0';
        return OK;
    }
    

     

    // Test program for getLine().
    
    int main (void) {
        int rc;
        char buff[10];
    
        rc = getLine ("Enter string> ", buff, sizeof(buff));
        if (rc == NO_INPUT) {
            // Extra NL since my system doesn't output that on EOF.
            printf ("\nNo input\n");
            return 1;
        }
    
        if (rc == TOO_LONG) {
            printf ("Input too long [%s]\n", buff);
            return 1;
        }
    
        printf ("OK [%s]\n", buff);
    
        return 0;
    }
    

    Testing it with various combinations:

    pax> ./prog
    Enter string>[CTRL-D]
    No input
    
    pax> ./prog
    Enter string> a
    OK [a]
    
    pax> ./prog
    Enter string> hello
    OK [hello]
    
    pax> ./prog
    Enter string> hello there
    Input too long [hello the]
    
    pax> ./prog
    Enter string> i am pax
    OK [i am pax]
    

    What I would do is to use this function to get a line safely, then simply use:

    sscanf (buffer, "%f %f", &real, &img)
    

    to get the actual values (and check the count).


    In fact, here's a complete program which is closer to what you want:

    #include <stdio.h>
    #include <string.h>
    
    #define OK       0
    #define NO_INPUT 1
    #define TOO_LONG 2
    static int getLine (char *prmpt, char *buff, size_t sz) {
        int ch, extra;
    
        // Get line with buffer overrun protection.
        if (prmpt != NULL) {
            printf ("%s", prmpt);
            fflush (stdout);
        }
        if (fgets (buff, sz, stdin) == NULL)
            return NO_INPUT;
    
        // If it was too long, there'll be no newline. In that case, we flush
        // to end of line so that excess doesn't affect the next call.
        if (buff[strlen(buff)-1] != '\n') {
            extra = 0;
            while (((ch = getchar()) != '\n') && (ch != EOF))
                extra = 1;
            return (extra == 1) ? TOO_LONG : OK;
        }
    
        // Otherwise remove newline and give string back to caller.
        buff[strlen(buff)-1] = '\0';
        return OK;
    }
    

     

    int main (void) {
        int i = 1, rc;
        char prompt[50], buff[50];
        float real, imag;
    
        while (1) {
            sprintf (prompt, "\nEnter real and imaginary for #%3d: ", i);
            rc = getLine (prompt, buff, sizeof(buff));
            if (rc == NO_INPUT) break;
            if (*buff == '\0') break;
    
            if (rc == TOO_LONG) {
                printf ("** Input too long [%s]...\n", buff);
            }
    
            if (sscanf (buff, "%f %f", &real, &imag) == 2) {
                printf ("Values were %f and %f\n", real, imag);
                i++;
            } else {
                printf ("** Invalid input [%s]\n", buff);
            }
        }
    
        return 0;
    }
    

    along with a test run:

    pax> ./testprog
    
    Enter real and imaginary for #  1: hello
    ** Invalid input [hello]
    
    Enter real and imaginary for #  1: hello there
    ** Invalid input [hello there]
    
    Enter real and imaginary for #  1: 1
    ** Invalid input [1]
    
    Enter real and imaginary for #  1: 1.23 4.56
    Values were 1.230000 and 4.560000
    
    Enter real and imaginary for #  2:
    
    pax> _
    
    0 讨论(0)
  • 2020-11-30 10:13

    There's a way to do what you want using just scanf:

    int readCoefficents(double complex *c) {
        int i = 0;
        double real;
        double img;
        char buf[2];
        while (scanf("%1[\n]", buf) == 0) {         // loop until a blank line or EOF
            if (scanf("%lf %lf", &real, &img) == 2) // read two floats
                c[i++] = real + img * I;
            scanf("%*[^\n]");                       // skip the rest of the line
            scanf("%*1[\n]");                       // and the newline
        }
        c[i++] = 1 + 0*I; // most significant coefficient is assumed to be 1
        return i;
    }
    

    If the user only enters 1 float on a line, it will read the next line for the second value. If any random garbage is entered, it will skip up to a newline and try again with the next line. Otherwise, it will just go on reading pairs of float values until the user enters a blank line or an EOF is reached.

    0 讨论(0)
  • 2020-11-30 10:14

    Instead of

    while(scanf("%f %f", &real, &img) == 2)
    

    try

    while(scanf("%f %f%*c", &real, &img) == 2)
    
    
    scanf("%f%*c", &myfloat); // will read a float and all eventual characters after it
    
    0 讨论(0)
  • 2020-11-30 10:16

    Use fgets to read console input:

       int res = 2;
       while (res == 2) {
           char buf[100];
           fgets(buf, sizeof(buf), stdin);
           res = sscanf(buf, "%f %f", &real, &img);
           if (res == 2)
               c[i++] = real + img * I;
       }
       c[i++] = 1 + 0*I; // most significant coefficient is assumed to be 1
       return i;
    
    0 讨论(0)
提交回复
热议问题