fscanf and feof: unexpected behavior

Question:

I am trying to store a .txt file in char type variables in C, the problem is that the result when compiling it prints the last line twice and I do not understand the reason.

  • In the .txt file I have the following:
123.22.0.212 255.255.0.0
2.169.73.5 255.255.0.0
2.50.10.36 255.255.192.0
  • Result on Compiling is as follows:
123.22.0.212 255.255.0.0
2.169.73.5 255.255.0.0
2.50.10.36 255.255.192.0
2.50.10.36 255.255.192.0
  • Code in C:
#include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE * archivo = fopen("direcciones.txt", "rb");    

    if(archivo == NULL)
    {
        perror("Error en la apertura del archivo");
        return 1;
    }

    /*leyendo caracter por caracter*/
    char ip[12];
    char mask[12];

    while( feof(archivo) == 0)
    {
        fscanf(archivo, "%s%s", &ip, &mask);
        printf("%s %s\n", ip, mask);
    }

    fclose(archivo);
    printf("\n\nSe ha leido el archivo correctamente...");

    return 0;   
}   

Answer:

First, what you don't ask but is equally wrong:

Your test data is:

123.22.0.212 255.255.0.0
2.169.73.5 255.255.0.0
2.50.10.36 255.255.192.0

And your variables to store them

char ip[12];
char mask[12];

However, according to my accounts, 255.255.192.0 is 13 characters long . Your variables are badly dimensioned. And already put, 255.255.255.255 need 16 bytes . 15 for the characters themselves, and 1 more for the final 0 .

We continue:

char ip[16];
char mask[16];
...
fscanf(archivo, "%s%s", &ip, &mask);

In C, there is no concept of a buffer or continuous-memory-area . A formation or arrangement does not exist as such . Broadly speaking, it is a favor that the compiler does for you by reserving a chunk of memory … and gives you a pointer to that area .

In other words: ip and mask are already pointers . In fact, if you use &ip or &mask , the compiler will show you a nice warning:

warning: format %s expects argument of type char * , but argument has type char (*)[12]

Ok, now your problem: Very simple, feof( ) checks the file's eof flag, but this flag is only set when performing an operation , never before:

  1. The feof( ) checks that everything is fine.
  2. You read from the file.
  3. The feof( ) checks that everything is fine.
  4. Being already at the end of the file, fscanf( ) does not read anything (thus keeping the last thing you would have read. Now the eof flag is eof .
  5. The feof( ) detects the problem.

Your code, corrected, would look like this:

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

int main( ) {
  FILE * archivo = fopen( "direcciones.txt", "rb" );    

  if( archivo == NULL ) {
    perror( "Error en la apertura del archivo" );
    return 1;
  }

  char ip[16];
  char mask[16];

  while( 1 ) {
    fscanf( archivo, "%s%s", ip, mask );

    if( feof( archivo ) != 0 ) {
      break;
    }

    printf( "%s %s\n", ip, mask );
  }

  fclose( archivo );
  printf( "\nSe ha leido el archivo correctamente...\n" );

  return 0;   
}
Scroll to Top