How to sscanf to make sure the buffer is exactly what I wanted?
Asked Answered
L

1

9

I would like to sscanf a line and make sure that that there is nothing more then what I wanted in it. The code looks like this:

void parse_init_command(char *buffer, command *new_command) {
    if (sscanf(buffer, 
        "%s %d %d %d %d %d %d %d\n",
        new_command->name,
        &new_command->data[0],
        &new_command->data[1],
        &new_command->data[2],
        &new_command->data[3],
        &new_command->data[4],
        &new_command->data[5],
        &new_command->data[6]) != 8) {
        strncpy(new_command->name, "WRONG_INPUT", 15);
    }
}

When I get an input like:

INIT 9 11 3 1 1 1 9

everything is fine, but then an input like this

INIT 9 11 3 1 1 1 9 s

is also accepted. I thought that if I added "\n" everything would work fine, since I know that every input line ends with an EOL, but it didn't.

Loudmouthed answered 8/5, 2016 at 17:9 Comment(2)
scanf treats the new-line character as white space, just like tabs and spaces. You could read a ninth dummy value, a short string with enforced max. width (%2s) perhaps, and enforce that the number of conversions doesn't exceed 8.Pacheco
Is your buffer initialized before being passed into this function?Ontologism
M
2

Something like this could do it if your input always has a newline at the end. The code requires one extra char type and checks that it is \n, as well as the correct number of items scanned. It prints 1 for success - a slight variation to your function for the purpose of this example.

#include <stdio.h>

typedef struct {
    char name[100];
    int data[7];
} command;

int parse_init_command(char *buffer, command *new_command) {
    char eol = 0;
    int num = sscanf(buffer, "%s%d%d%d%d%d%d%d%c",
                                new_command->name,
                                &new_command->data[0],
                                &new_command->data[1],
                                &new_command->data[2],
                                &new_command->data[3],
                                &new_command->data[4],
                                &new_command->data[5],
                                &new_command->data[6],
                                &eol);
    return num == 9 && eol == '\n';
}

int main(void)
{
    char inp[50];
    command rec;
    fgets(inp, sizeof inp, stdin);
    printf("%d\n", parse_init_command(inp, &rec) );
    return 0;
}

Program sessions from keyboard:

INIT 9 11 3 1 1 1 9
1

INIT 9 11 3 1 1 1 9 s
0

Note there is no leading space before %c which would cause whitespace to be skipped, defeating the point of having it.

Mabellemable answered 8/5, 2016 at 17:31 Comment(1)
That will create a hard-to-explain error when the user types INIT 9 11 3 1 1 1 9 (with a space at the end.) I like @MOehm's solution better (in a comment to the OP).Irmgardirmina

© 2022 - 2024 — McMap. All rights reserved.