简体   繁体   中英

Using sscanf for reading from fgets

I'm still a bit new to programming and I'm getting this warning when I compile the program:

warning: too many arguments for format [-Wformat-extra-args]
int c = sscanf(Input, "%f %f %*[^\n]%*d", &start, &end, &rows);
                      ^~~~~~~~~~~~~~~~~~

This is my code:

fgets(Input, 256, stdin);
int count = 0;
char *token = strtok(Input, " \n\t");
count++;

while(token != NULL)
{
    token = strtok(NULL, " \n\t");
    count++;
}

if(count == 3)
{
    int c = sscanf(Input, "%f %f %*[^\n]%*d", &start, &end, &rows);
    if(c != 3)
    {
        printf("\nError: Illegal input!\n");
    }
}

What I'm trying to do is read three numbers if there are three separate strings. I know that sscanf can be used to validate input (as it returns the number of successful scans).

For example, these numbers are 1 6 8 .
And it should print "Illegal input" for an input like 0 ab 19 .

I have also tried storing the tokens into an array of character strings, but have an issue with validation in that.

So what I want to ask is, is this the right way to do it?

Thanks in advance.

Your code fails for 2 reasons:

  • The parse you perform with strtok() modifies the Input array, so the subsequent conversion with sscanf() will fail because only the first field will be seen.
  • The format string "%f %f %*[^\\n]%*d" contains 2 conversion specifications for float values and 2 conversions with suppressed storage. Passing 3 destination arguments is incorrect.

Here is how you can perform the conversion and the validation in a single call:

int read_values(void) {
    char input[256];
    char str[256];
    float start, end;
    int rows;
    char c;

    if (fgets(input, sizeof(input), stdin)) {
        *string = '\0';
        if (sscanf(input, "%f%f%d %c", &start, &end, &rows, &c) == 3) {
            // start, end and rows were read and converted properly
            // you might way to perform further validation steps on their values.
        } else
        if (sscanf(input, "%s%f%f%d %c", str, &start, &end, &rows, &c) == 4) {
            // there was an initial word before the 3 numbers
        } else {
            printf("Error: invalid input: %s", input);
            return -1;
        }
        return 0;
    } else {
        printf("Error: premature end of file\n");
        return -1;
    }
}

sscanf() will return 3 if and only if it can convert 2 floats and an integer and no other character is present on the line except trailing blanks. Leading blanks and blanks between the numbers are also ignored.

If the optional string can have multiple words, you can use an iterative approach: you can try and skip words until the parse succeeds or the input is completely consumed:

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

int read_values(void) {
    char input[256];
    float start, end;
    int i, rows;
    char c;

    if (fgets(input, sizeof(input), stdin)) {
        for (i = 0;;) {
            if (input[i] == '\0') {
                printf("Error: invalid input: %s", input);
                return -1;
            }
            if (sscanf(input + i, "%f%f%d %c", &start, &end, &rows, &c) == 3) {
                break;
            }
            i += strspn(input + i, " \t\n");   // skip white space
            i += strcspn(input + i, " \t\n");  // skip a word
        }
        // The initial string has `i` characters
        // start, end and rows were read and converted properly
        // you might want to perform further validation steps on their values.
        printf("string: %.*s\n", i, input);
        printf("start: %f\n", start);
        printf("end: %f\n", end);
        printf("rows: %d\n", rows);
        return 0;
    } else {
        printf("Error: premature end of file\n");
        return -1;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM