Reputation: 71
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.
Upvotes: 1
Views: 1695
Reputation: 144750
Your code fails for 2 reasons:
strtok()
modifies the Input
array, so the subsequent conversion with sscanf()
will fail because only the first field will be seen."%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;
}
}
Upvotes: 2