Search code examples
cstringscanf

scanf from a generated string


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?


Solution

  • 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