0

I'm trying to read multiple lines of vertices with varying length using fgets and sscanf.

(1,6),(2,6),(2,9),(1,9)
(1,5)

My program goes into an infinite loop stuck within the first vertex.

    char temp3[255];
    while(fgets(temp3, 255, fp)!= NULL){
        printf("Polygon %d: ", polycount);
        while(sscanf(temp3, "(%d,%d)", &polygonx[polycount][vertcount], &polygony[polycount][vertcount]) != EOF){
            sscanf(temp3, ",");
            printf("(%d,%d),",polygonx[polycount][vertcount], polygony[polycount][vertcount]);
            vertcount++;
        }
        vertcounts[polycount] = vertcount;
        vertcount = 0;
        polycount++;
    }

I must be able to feed the x and y values of the vertices into the polygon arrays, so i'm stuck with using sscanf. I'm also having a problem since I cant find anything on the internet that scans varying numbers of elements per line.

gkhnavarro
  • 446
  • 2
  • 14
  • 1
    `sscanf` reads the same thing over and over again causing an infinite loop. It doesn't advance as you think. – Spikatrix Sep 24 '15 at 12:50
  • Fixed sscanf earlier, along with @iharob's suggestions. My main problem was with my pointer not being updated after an iteration of fgets(). Thanks, anyway. :) – gkhnavarro Sep 24 '15 at 12:53

2 Answers2

5

It's because this

while(sscanf(temp3, "(%d,%d)", 
  &polygonx[polycount][vertcount], &polygony[polycount][vertcount]) != EOF)
 {
 }

is never going to be true I think, because scanf() returns the number of parameters succesfuly scanned, I would do this instead

while(sscanf(temp3, "(%d,%d)", 
  &polygonx[polycount][vertcount], &polygony[polycount][vertcount]) == 2)
 {
 }

Your code doesn't work because it does not satisfy the condition for sscanf() to return EOF, the following is from the manual page referenced at the end

The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs, in which case the error indicator for the stream (see ferror(3)) is set, and errno is set to indicate the error.

So it appears that you are not reaching the end if input before the first successful conversion or a matching failure occurs, which makes sense according to the contents of the file. And the second part applies only to file streams of course.

And instead of the sscanf(temp3, ",") which doesn't do what you think, you could do it like this

next = strchr(temp3, ',');
if (next != NULL)
    temp3 = next + 1;
else
    /* you've reached the end here */

This is a suggestion on how to parse this file

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

int
main(void)
{
    const char temp3[] = "(1,6),(2,6),(2,9),(1,9)\n(1,5)";
    char *source;
    int x, y;
    int count;
    source = temp3;
    while (sscanf(source, "(%d,%d)%*[^(]%n", &x, &y, &count) == 2)
    {
        /* this is just for code clarity */
        polygonx[polycount][vertcount] = x;
        polygony[polycount][vertcount] = y;
        /* Process here if needed, and then advance the pointer */
        source += count;
    }
    return 0;
}

The "%n" specifier captures the number of characters scanned so far, so you can use it to advance the pointer to the las position scanned in the source string.

And the "%*[^(" will skip all characters until the next '(' is found.

Please refer to sscanf(3) for more information on the "%n" specifier, and the %[ specifier.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
2

If successfully read sscanf will return 2 in this case . sscanf returns numbers of variables filled.

Check if it returns 2 which will indicate success here .

while(sscanf(temp3,"(%d,%d)",&polygonx[polycount][vertcount],&polygony[polycount]][vertcount]) != EOF)

Instead of this , check like this -

 while(sscanf(temp3,"(%d,%d)%*c",&polygonx[polycount][vertcount],&polygony[polycount]][vertcount])== 2)
                             ^ to exclude the comma after it             

also to ignore ',' after the coordinates , you use -

sscanf(temp3, ",");

is not correct . In the above sscanf you can read it and discard it as well by using %*c specifier.

ameyCU
  • 16,489
  • 2
  • 26
  • 41
  • 1
    `"%*c"` is ok if there is just one `,` or any other character after the end of the tuple, `"%*[^(]"` would be more robust. – Iharob Al Asimi Sep 24 '15 at 12:30
  • I don't think `%*c` does anything useful here. The `sscanf` would behave the same way if it wasn't there. – Spikatrix Sep 24 '15 at 12:36
  • 1
    @iharob I guess the format of code is fixed . And `(` will be matched in next iteratation . So we don't have to worry about that . – ameyCU Sep 24 '15 at 12:41
  • @CoolGuy Nope , you were correct. I did really something dumb. Did really a blunder . :| – ameyCU Sep 24 '15 at 13:13
  • The solution in your answer won't work. `sscanf` doesn't advance on reading. Once the `sscanf` in your answer returns 2, you'll get an infinite loop. – Spikatrix Sep 24 '15 at 13:24