Home > Net >  scanf from a generated string
scanf from a generated string

Time:12-21

I need to create a program to read a file line by line and in each line scan some data. for example in a line like :

# 2 (x1,y1)(x2,y2)

i need x1,y1 and x2,y2 my code is

    char firstCharacter;
    char line[100];
    scanf("%c",&firstCharacter);
    while ((fgets(line, sizeof line, stdin) != NULL) && (line[0] != '\n')){
        if(firstCharacter == '#'){
            int nu_deadend;
            sscanf(line,"%d",&nu_deadend);
            for (int i = 0; i < nu_deadend; i  ) {
                int x,y;
                sscanf(line,"(%d,%d)",&x,&y);
                printf("x: %d y: %d\n",x,y);
            }
        }
    }
    return 0;

but from input:

# 2 (2,3)(3,4)

it outputs:

x:0 y:0
x:0 y:0

expected output:

x:2 y:3
x:3 y:4

what am I doing wrong?

CodePudding user response:

From my top comment ...

Unlike scanf which continues where it left off, sscanf will start at the buffer it is given. So, you probably need to use (e.g.) char *cp = line; and then use and advance cp to point to the next token.

sscanf is ill-suited to this because it returns a count and not the number of bytes consumed.

Better to use fgets, cp, and strtok and pass the return value of strtok to sscanf

Also, you never reset firstCharacter for the second line (i.e. I presume each line starts with #)


Here is a refactored version. It is annotated:

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

#ifdef DEBUG
#define dbgprt(_fmt...)         printf(_fmt)
#else
#define dbgprt(_fmt...)         do { } while (0)
#endif

int
main(void)
{
    char *tok;
    char line[100];

    // FORMAT:
    //  # <count> (x,y)(x,y)...
    while (fgets(line, sizeof line, stdin) != NULL) {
        dbgprt("LINE: %s",line);

        // get first token
        tok = strtok(line," \n");
        if (tok == NULL)
            break;

        // this must be "#"
        if (*tok != '#')
            continue;

        // get the count
        int nu_deadend;
        tok = strtok(NULL," \n");
        sscanf(tok, "%d", &nu_deadend);
        dbgprt("NUM: %d\n",nu_deadend);

        // get "(x,y)(x,y)(x,y)"
        tok = strtok(NULL," \n");

        for (int i = 0; i < nu_deadend; i  ) {
            int x, y;

            dbgprt("TOK: '%s'\n",tok);
            sscanf(tok, "(%d,%d)", &x, &y);
            printf("x: %d y: %d\n", x, y);

            // advance past the end of the current (x,y)
            tok = strchr(tok,')');
            if (tok == NULL)
                break;
              tok;
        }
    }

    return 0;
}

Here is the test input I used:

# 2 (2,3)(3,4)
# 3 (1,7)(9,2)(8,3)

Here is the debug output:

LINE: # 2 (2,3)(3,4)
NUM: 2
TOK: '(2,3)(3,4)'
x: 2 y: 3
TOK: '(3,4)'
x: 3 y: 4
LINE: # 3 (1,7)(9,2)(8,3)
NUM: 3
TOK: '(1,7)(9,2)(8,3)'
x: 1 y: 7
TOK: '(9,2)(8,3)'
x: 9 y: 2
TOK: '(8,3)'
x: 8 y: 3

And, here is the clean output:

x: 2 y: 3
x: 3 y: 4
x: 1 y: 7
x: 9 y: 2
x: 8 y: 3

CodePudding user response:

You are reading the "#" from input. What is left in input (including the initial "2") is read into the buffer.

In contrast to the input stream, the string line you are using still contains the already successfully scanned initial "2" after sscanf(line,"%d",&nu_deadend);, instead of loosing it with a successful scan.

So your attempt to scan the "(...)" needs to take the "2" into account.

E.g. like

sscanf(line,"%*d (%d,%d)",&x,&y);

for the first "()".

The second one would either require more elaborate ignoring, or need to start scanning at an appropriate index for the relevant "(" inside the string.
Since you need to loop, the elaborate ignoring does not help. You will have to first search for the right "(" and then do the scanning.

  • Related