Jorge
Jorge

Reputation: 2325

Can't understand this infinite loop

I have this code to read a file and then print each line but when i run it it keeps printing '1 ; 0 ; ; 0 ; 0 ; 0' infinitely. The input file has this in it:

1 ; Visitante ; 10 ; 19 ; 2 ; 3
2 ; 1 ; Funcionario ; 8 ; 0 ; 2
3 ; 2 ; Diretor ; 12 ; 19 ; 4
4 ; Visitante ; 8 ; 0 ; 3 ; 2

The code:

#include <stdio.h>
#include <stdlib.h>


void readInput() {
   FILE * fp;
   int id = 0, acompanhantes = 0, entrada = 0, saida = 0, servico = 0;
   char tipo[256] = {};

   if ((fp = fopen("input.txt", "r")) == NULL) {
     printf("Erro a abrir o ficheiro, o programa vai terminar...\n");
     exit(1);
   }

   while ((fscanf(fp,"%d ; %d ; %s ; %d ; %d ; %d\n", &id, &acompanhantes, tipo, &entrada, &saida, &servico)) != EOF) {
     printf("%d ; %d ; %s ; %d ; %d ; %d\n", id, acompanhantes, tipo, entrada, saida, servico);
   }

   fclose(fp);

}

int main() {
  readInput();
}

Upvotes: 0

Views: 99

Answers (1)

Schwern
Schwern

Reputation: 165606

You've hit a common gotcha of the scanf functions. If they fail to scan they'll just keep trying to rescan the same input over and over again.

In your case the first line of your file does not match your format.

1 ; Visitante ; 10 ; 19 ; 2 ; 3
"%d ; %d ; %s ; %d ; %d ; %d\n"

So fscanf matches the first column, and fails on the second. It returns the number of items matched: 1. That isn't EOF so it repeats on the same line over and over again.

Normally you'd fix this by checking fscanf returns the total number of items to be scanned. fscanf( ... ) >= 6 But this doesn't solve that you have a file with different fields in it.

First, we can solve a lot of potential issues by separating reading the line and parsing the line. Use fgets + sscanf instead of trying to do them at the same time with fscanf. Not only does this avoid infinite looping, but it gives us more room to play with the parsing.

Then we can read the line once, and try to parse it with the various formats until one works.

char line[4096];
while (fgets( line, sizeof(line), fp) != NULL) {
    if(
        ( sscanf(line,"%d ; %d ; %s ; %d ; %d ; %d\n", &id, &acompanhantes, tipo, &entrada, &saida, &servico) >= 6 ) ||
        ( sscanf(line,"%d ; %s ; %d ; %d ; %d ; %d\n", &id, tipo, &acompanhantes, &entrada, &saida, &servico) >= 6 )
    ) {
        printf("%d ; %d ; %s ; %d ; %d ; %d\n", id, acompanhantes, tipo, entrada, saida, servico);
    }
    else {
        fprintf(stderr, "Could not parse %s.\n", line);
    }
}

Upvotes: 3

Related Questions