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.