Leyendo un archivo C, lee una línea extra, ¿por qué?

No sé exactamente por qué un puntero de archivo lee una línea adicional de un archivo, específicamente la última línea, aquí está el código:

FILE *fp ; fp = fopen ("mac_ip.txt", "r") ; int mac; char *ip = (char *) malloc(15); while(!feof(fp)){ fscanf(fp,"%i",&mac); fscanf(fp,"%s",ip); printf("MAC: %i\n",mac); printf("IP: %s\n",ip); } 

y el archivo tiene exactamente 20 líneas, pero la línea 20 se imprime dos veces.

¿Cual es el error?

Gracias por adelantado.

Después de que hayas hecho las dos lecturas en la línea veinte, has llegado al final del archivo, pero el sistema no lo sabe. feof solo se activará cuando intentes superar el final del archivo, no cuando estés exactamente en él …

Además, puede tener un final de línea (CR o CR-LF) en la línea 20 que solo pasará con otro bash de lectura.

La solución es leer la línea de una sola vez (hay un comando C específico para esto) y luego analizarla para obtener sus datos. Si la lectura de toda la línea falla, entonces has llegado al final.

Porque después de leer los dos últimos valores, todavía no has alcanzado EOF. Así que el bucle continúa. En la siguiente pasada del bucle, fscanf en realidad no lee la última línea por segunda vez como aparece, los fscanfs fallan, pero los printfs imprimen los valores de la pasada anterior del bucle.

feof no “sabe” está al final del archivo hasta que intenta leer un poco más. Ya que fscanf te dice cuántos artículos obtuvo, puedes usar este simple truco:

 for(;;){ if (fscanf(fp,"%i%s", &mac, ip) != 2) break; printf("MAC: %i\n",mac); printf("IP: %s\n",ip); } 

Su código se parece al siguiente ejemplo

 #include  int main(void) { char buffer[256]; FILE * myfile; myfile = fopen("some.txt","r"); while (!feof(myfile)) { fgets(buffer,256,myfile); printf("%s",buffer); } fclose(myfile); return 0; } 

desde

http://www.friedspace.com/feof.html

Es mejor probar el valor de retorno de fscanf antes de imprimir el resultado. Apuesto a que en la última iteración de su bucle, las llamadas a fscanf fallan y usted imprime los últimos resultados devueltos.

 FILE *fp ; int mac; char ip[15]; fp = fopen ("mac_ip.txt", "r") ; if (!fp) return; while(1){ if (fscanf(fp,"%i",&mac) < 1) break; if (fscanf(fp,"%s",ip) < 1) break; printf("MAC: %i\n",mac); printf("IP: %s\n",ip); } fclose (fp); 

fscanf () devuelve el número de asignaciones que está enojado (o -1 en eof). Al utilizar el valor de retorno, no necesita la función eof (). Por cierto, no creo que puedas leer una dirección MAC en un int. ¿Quizás necesitas leer eso también en una cadena?

Explicación: feof () no hace lo que espera el OP. feof () solo debe inspeccionarse después de que una de las operaciones de archivo haya fallado. En la mayoría de los casos no necesitas feof ().