2017-12-15 3 views
1

Ich bin ein erschwerendes Problem habe, die ich nicht verstehen kann,fscanf! = EOF Clang-Compiler, anomale Verhalten

void file_count(FILE* stream,int* const num) 
{ 
    int temp; 
    while((fscanf(stream,"%d",&temp))!=EOF) 
    { 
     (*num)++; 
    } 
} 

Mit diesem Stück Programm, las ich von einer Datei in ihn alle Zahlen unter , und wenn ich eine Zahl nehme, erhöht sich ein Zähler, so dass ich zählen kann, wie viele Elemente in der Datei enthalten sind.

In dieser Datei gibt es 6 Zahlen, aber wenn ich diesen Code laufen lässt, springt der Zähler auf 32777 ... Wenn ich es mit gcc kompiliere, gibt es kein Problem und der Zähler ist 6 wie erwartet. Ist das ein Klirren? Ist das ein Merkmal, das mir nicht bekannt ist?

Die Datei enthält:

22 30 30 21 25 29 

Der gesamte Code:

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

typedef char* string; 
typedef struct student 
{ 
    int flag; 
    char name[25]; 
    char surname[25]; 
    char dorm[25]; 
    int* grades; 
} 
Student; 

void check_input(const int argc,const string* const argv); 
void check_file(FILE* stream); 
void file_count(FILE* stream,int* const num); 
void update_student(const string* const infos,Student* const student,const int grades,FILE* stream); 
void print_student(FILE* stream,Student const student,const int grades); 

int main(int argc, string argv[]) 
{ 
    check_input(argc,argv); 
    FILE* one,* two; 
    string info[]={"David","Malan","Mather"}; 
    Student student; 
    int grades; 
    one=fopen(argv[1],"r"); 
    check_file(one); 
    file_count(one,&grades); 
    update_student(info,&student,grades,one); 
    fclose(one); 
    two=fopen(argv[2],"w"); 
    check_file(two); 
    print_student(two,student,grades); 
    fclose(two); 
    free(student.grades); 
    system("cat out"); 
    return 0; 
} 

void check_input(const int argc,const string* const argv) 
{ 
    if(argc!=3) 
    { 
     printf("\x1B[31mError: %s takes two arguments!\x1B[0m\n",argv[0]); 
     exit(EXIT_FAILURE); 
    } 
} 

void check_file(FILE* stream) 
{ 
    if(stream==NULL) 
    { 
     printf("\x1B[31mError:invalid file.\x1B[0m\n"); 
     exit(EXIT_FAILURE); 
    } 
} 

void file_count(FILE* stream,int* const num) 
{ 
    int temp; 
    printf("reading file...\n"); 
    while((fscanf(stream,"%i",&temp))!=EOF) 
    { 
     (*num)++; 
    } 
    printf("\x1B[33mthe value read were %i\x1B[0m\n",*num); 
} 

void update_student(const string* const infos,Student* const student,const int grades,FILE* stream) 
{ 
    rewind(stream); 
    student->grades=malloc(grades*sizeof(int)); 
    strcpy(student->name,infos[0]); 
    strcpy(student->surname,infos[1]); 
    strcpy(student->dorm,infos[2]); 
    student->flag=0; 
    for(int i=0;i<grades;i++) 
    { 
     fscanf(stream,"%i",&student->grades[i]); 
    } 
} 

void print_student(FILE* stream,Student const student,const int grades) 
{ 
    printf("Writing to file..\n"); 
    fprintf(stream,"%i %s %s %s ",student.flag,student.name,student.surname,student.dorm); 
    for(int i=0;i<grades;i++) 
    { 
     fprintf(stream,"%i ",student.grades[i]); 
    } 
    printf("\x1B[32mFile successfully written..\x1B[0m\n"); 
} 
+0

Im Code, den Sie nicht angezeigt haben, kann eine beliebige Anzahl von Fehlern auftreten. Siehe [minimales, vollständiges und überprüfbares Beispiel] (https://stackoverflow.com/help/mcve). – user3386109

+0

Zeigen Sie mehr Code und vorzugsweise die Datei an, die Sie als Eingabe verwenden. – AnT

+0

Wahrscheinlich trifft man etwas, das keine Ganzzahl ist (höchstwahrscheinlich das Ende der Zeile, in der Tat), so dass "fscanf" es nicht konsumiert, so dass man dort hängenbleibt. –

Antwort

4

Ihr Code ist gefährlich, da eine falsche Datei, um sie in eine Endlosschleife sendet.

Sobald fscanf mit %d einen Eingang findet, die nicht als int interpretiert werden kann, gibt die Funktion Null, ohne dass Fortschritte machen die Eingabe auf raubend. Daher erreicht die Schleife nie EOF.

Sie können dieses Problem beheben, indem nur so lange Schleife, wie der Eingang verbraucht wird:

while(fscanf(stream,"%d",&temp) == 1) { 
    ... 
} 

Jetzt müssen Sie einen Weg, um den Anrufer zu kommunizieren, wenn die Zahl korrekt ist oder nicht. Sie können das tun, indem Sie Rückkehr ein, wenn EOF erreicht ist, und sonst Null:

int file_count(FILE* stream,int* const num) { 
    int temp, last; 
    while((last = fscanf(stream,"%d",&temp)) == 1) { 
     (*num)++; 
    } 
    return last == EOF; 
} 

ich mit fscaf==1 versuchte es erreicht noch 32777

Dies geschieht, weil Sie nicht grades in dem Anrufer initialisiert werden . Sie sollten es als int grades = 0 definieren oder *num = 0 hinzufügen, bevor Sie die Schleife in file_count eingeben.

+0

ich versuchte mit fscaf == 1 es erreicht immer noch 32777 –

+1

@GiannandreaVicidomini Das ist, weil Sie 'Grade' im Anrufer nicht initialisieren. Sie sollten 'int grade = 0 'eingeben. – dasblinkenlight

+1

@FredLarson Sie haben Recht, ich habe nach '% d' Platz hinzugefügt, um sicherzustellen, dass der Endplatz verbraucht ist. – dasblinkenlight

0

Die aktuelle ISO-C-Standard definiert den Rückgabewert von fscanf() als

Die fscanf Funktion den Wert des Makro EOF zurückgibt, wenn ein Eingangsfehler auftritt, bevor die erste Umwandlung (falls vorhanden) durchgeführt hat. Andernfalls gibt die Funktion die Anzahl der zugewiesenen Eingabeelemente zurück, die im Falle eines frühzeitigen Übereinstimmungsfehlers weniger als vorgesehen oder sogar null sein können.

Verbatim Zitat aus dem ISO-C Standard (kein öffentlicher Link zur Verfügung, die Norm nicht öffentlich AFAIK ist)

Wenn es Daten zu lesen, aber dass Daten nicht erfolgreich angepasst werden, wird diese Funktion zurückkehrt 0. Es gibt nur EOF zurück (normalerweise -1), wenn keine Daten zu lesen sind, weil der Stream, von dem Sie lesen, im EOF-Zustand ist oder einen anderen Lesefehler hatte.

Also, wenn Sie eine Datei wie das hatte:

23 a 57 

Die Schleife wird niemals enden. Beim ersten Scan wird 23 gelesen und 1 zurückgegeben (ein übereinstimmender Wert). Beim nächsten Aufruf wird 0 zurückgegeben, da a nicht mit einer Ganzzahl abgeglichen werden kann. Der Dateizeiger wird jedoch nicht über a hinaus verschoben. Beim nächsten Anruf versucht es wieder a und es wird erneut fehlschlagen. Das geht endlos weiter.

+0

Warum funktioniert es dann mit GCC zurückkehrenden EOF? –

+0

@FredLarson Sie haben Recht, die andere Seite erwähnte diesen Fall nicht; Ich habe eine Kopie des ISO-C-Standards (C11), also habe ich das Zitat durch eines ersetzt, das per Definition korrekt sein muss (es ist schließlich der Standard, es definiert, was richtig und was falsch ist). – Mecki