0

I was reading about sscanf and i came across this:

Return Value Each of these functions [including s_sscanf()] returns the number of fields that are successfully converted and assigned; the return value does not include fields that were read but not assigned. A return value of 0 indicates that no fields were assigned. The return value is EOF for an error or if the end of the string is reached before the first conversion.

I am doing error checking for my input file and i wanna make sure i get a valid line so i tried using sscanf but how do i make sure there are no more fields in the line than i expect. So if i have 3 values in a line but i only need two then that is an invalid line for me but when i use sscanf i only read in 2 variables and the rest are ignored. How do i check the entire line making sure there is no garbage in the line but im not sure what to expect so its not like i can add another variable cause the user can input anything. Someone mentioned to me that you can use * in your sscanf function but im not really sure how i haven't been able to find it anywhere where it is being implemented in code.

  • Rather explaining your code theoretically please post your code and its input and output. It is hard to digest otherwise. – kiran Biradar Oct 18 '18 at 12:58
  • there is no code im just trying to understand the return value of sscanf @kiranBiradar and what happens if you have extra fields that are not assigned and how you can check for errors – programmergirl Oct 18 '18 at 12:59
  • if you have extra fields, scanf stops before it can scan them. You probably need `fgets` then `strtok` – Jean-François Fabre Oct 18 '18 at 13:01
  • _"its not like i can add another variable"_ - why not? Add a dummy variable for `%c` format and check if (in this case) `sscanf` returns 2 (OK) or 3 (garbage at end of line) – ReAl Oct 18 '18 at 13:02
  • but what if there is more than 3 i cant keep adding a dummy variablel? can i ? @ReAl – programmergirl Oct 18 '18 at 13:04
  • Is it valuable — 3, 4 or more — if you only need 2? If you need 2 variables, sscanf must return 2 for OK. 1="not enough input data", 3="three or more but anyway more than two" – ReAl Oct 18 '18 at 13:10
  • See [this answer of mine to an older question](https://stackoverflow.com/a/4160001/25324). – pmg Oct 18 '18 at 14:23
  • ill check it out thanks!! @pmg – programmergirl Oct 18 '18 at 14:25

2 Answers2

1

The scanf() family of functions returns the number of successful assignments made. If code is expecting three input items there is no way to tell from the value returned by sscanf() alone whether three or more input items were provided.

The scanf() functions operate by reading a character, attempting to match that character, making an assignment if applicable, then moving to the next character or returning from the function call. There is a conversion specifier, %n, that stores the number of characters read in this process so far (without incrementing the number of characters read). This conversion specifier can be used to determine if the input has been exhausted by the call to sscanf().

The code below provides a demonstration. Lines of input gathered by fgets() contain a newline, unless the input is too large to fit in the buffer array. Here buffer[] is large enough to store reasonably-sized inputs, but more robust code would handle oversized inputs more carefully. When sscanf() scans the input string, each character is read in turn until a failing match occurs or the end of the string is reached, so the number of read characters expected after matching "%d %d %d %n" is the same as the length of the input string, including any trailing whitespace characters.

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

#define BUF_SZ  1024

int main(void)
{
    char buffer[BUF_SZ];
    int x, y, z;
    int pos;

    printf("Enter three integers: ");
    fflush(stdout);

    // get user input
    if (fgets(buffer, sizeof buffer, stdin) != NULL) {

        // first check: does input match 3 integers?
        if (sscanf(buffer, "%d %d %d %n", &x, &y, &z, &pos) != 3) {
            puts("Incorrectly formatted input");
        } else {
            // second check: did sscanf() finish at the end of the buffer?
            int expected = strlen(buffer);
            if (pos != expected) {
                puts("Extra input in buffer");
                printf("expected = %d, pos = %d\n", expected, pos);
        } else {
            // everything OK
            printf("You entered: %d, %d, %d\n", x, y, z);
            }
        }
    }

    return 0;
}

Sample interactions:

>$ ./a.out 
Enter three integers: 1 2 3
You entered: 1, 2, 3
>$ ./a.out 
Enter three integers: 1 2
Incorrectly formatted input
>$ ./a.out 
Enter three integers: 1 2 3 4
Extra input in buffer
expected = 8, pos = 6

If it is desired to disallow even trailing whitespace characters, "%d %d %d%n" can be used instead. Note that in order for this to work, the newline character must be removed from buffer[] so that it is not counted as extra input. One typical way to do this is by using buffer[strcspn(buffer, "\r\n")] = '\0':

int main(void)
{
    char buffer[BUF_SZ];
    int x, y, z;
    int pos;

    printf("Enter three integers: ");
    fflush(stdout);

    // get user input
    if (fgets(buffer, sizeof buffer, stdin) != NULL) {

        // first check: does input match 3 integers?
        if (sscanf(buffer, "%d %d %d%n", &x, &y, &z, &pos) != 3) {
            puts("Incorrectly formatted input");
        } else {
            // remove trailing newline character
            buffer[strcspn(buffer, "\r\n")] = '\0';
            // second check: did sscanf() finish at the end of the buffer?
            int expected = strlen(buffer);
            if (pos != expected) {
                puts("Extra input in buffer");
                printf("expected = %d, pos = %d\n", expected, pos);
        } else {
            // everything OK
            printf("You entered: %d, %d, %d\n", x, y, z);
            }
        }
    }

    return 0;
}
ad absurdum
  • 19,498
  • 5
  • 37
  • 60
0

You may, first of all, give the conversion specifiers for the values that you are sure must be present, and then add an "assignment-allocation modifier" to capture any remaining input. I am not sure whether you are talking about sscanf, fscanf or scanf; I will just use scanf to illustrate. The following program reads 2 integers, and places any remaining input in a string variable, the size of which is dynamically allocated:

Update: Using sscanf instead of scanf.

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
    int a,b;
    char *s;
    int n;
    char src[]="1 2 This is the remainder";
    n=sscanf(src,"%d %d %m[^\n]",&a,&b,&s);
    if(n>2)
        printf("s=%s\n", s), free(s);
    return 0;
}

$ ./a.out 
s=This is the remainder
Tano Fotang
  • 449
  • 3
  • 7