Externe Datei erstellen/lesen



  • Guten Abend!^^

    Ich arbeite momentan an einem kleinen Projekt, geschrieben in C.

    Der ganze Ablauf des Projekts ist erstmal irrelevant, es geht um ein Spiel, welches auch eine Highscoreliste hat.

    Am Ende des Spiels wird diese mit fscanf eingelesen um den Punktestand auf dem letzten Platz mit dem eben erreichten zu vergleichen.
    Jetzt besteht aber das Problem, dass die Highscoreliste, sofern es sich um das erste Spiel handelt, noch nicht existiert, was dazuführt, dass ich sie nicht mit "r" einlesen kann sondern mit "w" erstellen muss. Wenn ich sie aber jede Runde mit "w" neuerstelle, werden die alten Werte überschrieben bzw. vernichtet, daher dachte ich mir.. funktioniert es vllt mit einem "if":

    void scannen(void){  /*Liest die 'alte Highscoreliste ein*/
       FILE *smth=fopen("Highscoreliste.txt", "r");
        if((smth = fopen ("Highscoreliste.txt", "r")) == NULL){
        FILE *smth=fopen("Highscoreliste.txt", "w");
        }
        int i;
        for ( i=0; i<6; i++){
            fscanf(smth, "%s\n" , abc[i].name);
            fscanf(smth, "%d\n" , &abc[i].punkte);
    
        }
        fclose(smth);
    }
    

    Leider funktioniert dies nicht und führt zu einem Programmabsturz.... Hat jmd eine Idee wie ich dieses Problem lösen kann??

    Wäre dankbar für jede Hilfe.
    Danke schonmal! 😃



  • void scannen(void){  /*Liest die 'alte Highscoreliste ein*/
       FILE *smth=fopen("Highscoreliste.txt", "r");
        if((smth == NULL){
            fclose(smth);
            smth=fopen("Highscoreliste.txt", "w");
        }
        else // fscanf macht logischerweise nur dann sinn, wenn die datei bereits existiert und zum lesen geöffnet ist.
        {
            int i;
            for ( i=0; i<6; i++){
                fscanf(smth, "%s\n" , abc[i].name); // woher kommt das struct "abc"? nirgends deklariert!
                fscanf(smth, "%d\n" , &abc[i].punkte);
    
        }
        fclose(smth);
    }
    

    abc???



  • geschweifte klammer zu vergessen.

    void scannen(void){  /*Liest die 'alte Highscoreliste ein*/
       FILE *smth=fopen("Highscoreliste.txt", "r");
        if((smth == NULL){
            fclose(smth);
            smth=fopen("Highscoreliste.txt", "w");
        }
        else // fscanf macht logischerweise nur dann sinn, wenn die datei bereits existiert und zum lesen geöffnet ist.
        {
            int i;
            for ( i=0; i<6; i++){
                fscanf(smth, "%s\n" , abc[i].name); // woher kommt das struct "abc"? nirgends deklariert!
                fscanf(smth, "%d\n" , &abc[i].punkte);
            } // <--
    
        }
        fclose(smth);
    }
    

    wird trotzdem nicht funktionieren, weil abc nirgends deklariert wird.



  • Tipp: Öffne die Datei mit fopen("Highscoreliste.txt", "a+") .



  • abcdefg schrieb:

    Tipp: Öffne die Datei mit fopen("Highscoreliste.txt", "a+") .

    int scannen( abc /* hier muss irgendwas mit abc stehen, sonst funktioniert das ganze nicht */ ){  /*Liest die 'alte Highscoreliste ein*/
       FILE *smth=fopen("Highscoreliste.txt", "a+");
        if((smth == NULL){
            return 1; // fehler, datei konnte nicht geöffnet werden
        }
        int i;
        for ( i=0; i<6; i++){
            fscanf(smth, "%s\n" , abc[i].name); // woher kommt das struct "abc"? nirgends deklariert!
            fscanf(smth, "%d\n" , &abc[i].punkte);
            } // <--
    
        fclose(smth);
    }
    

    wtf ist abc?



  • Es ist nirgends deklariert, weil das nicht annähernd der ganze Code ist, dieser beträgt weit über 100 Zeilen.

    struct highscore{
    	char *name;
    	int punkte;
    }abc[6];
    

    Das ist die Deklaration zu abc.

    Und danke für deinen Vorschlag, aber leider führt auch dieser zu einer Fehlermeldung sobald diese Funktion arbeiten sollte.

    Lasse ich den Teil weg, funktioniert es und sieht so aus, aber erbringt eben das Problem, dass der alte Eintrag verloren geht.

    void scannen(void){  /*Liest die 'alte Highscoreliste ein*/
    	FILE *smth=fopen("Highscoreliste.txt", "w");
            int i;
    	for ( i=0; i<6; i++){
    		fscanf(smth, "%s\n" , abc[i].name);
    		fscanf(smth, "%d\n" , &abc[i].punkte);
    
    	}
    	fclose(smth);
    }
    


  • int scannen( struct highscore *abc[]){
       FILE *smth=fopen("Highscoreliste.txt", "a+");
        if((smth == NULL){
            return 1; // fehler, datei konnte nicht geöffnet werden
        }
        int i;
        for ( i=0; i<6; i++){
            fscanf(smth, "%s\n" , abc[i].name);
            fscanf(smth, "%d\n" , &abc[i].punkte);
        }
        fclose(smth);
        return 0; // alles war erfolgreich
    }
    

    sorry, habe grad keine zeit, das ganze selbst zu kompilieren. so sollte das funktionieren.

    falls nicht, dann liegt das an dem doppelpointer.



  • Eben getestet. auch "a+" führt zu einer Fehlermeldung.

    So, dann eben ein grober Überblick über meinen Highscore und die zuständigen Funktionen:

    scannen: Liest die alte Liste ein
    eintragen: Ermöglicht es dem Spieler, seinen Namen einzugeben, die Punkte werden direkt übernommen - global. Zusätzlich vergleicht diese Funktion den Punktestand des jetzigen Spielers, mit dem des Spielers auf Platz 5 und ordnet die neuen Werte dem 5. Platz zu, falls sie höher sind.
    sortieren: Bubblesort
    speichern: Schreibt die neu-sortierte Liste in die Datei.

    struct highscore{
    	char *name;
    	int punkte;
    }abc[6];
    
    void scannen(void){  /*Liest die 'alte Highscoreliste ein*/
    	FILE *smth=fopen("Highscoreliste.txt", "a+");
            int i;
    	for ( i=0; i<6; i++){
    		fscanf(smth, "%s\n" , abc[i].name);
    		fscanf(smth, "%d\n" , &abc[i].punkte);
    
    	}
    	fclose(smth);
    }
    
    void eintragen(void){ /*Hier kann man seinen Namen eintragen, Punkte werden übernommen*/
    	printf("Trag dich in den Highscore ein! Name:\n");
    	char *nome;
    	nome=malloc(10*sizeof(char));//--------------test
    	scanf("%9s", nome);//-----------------test
    	printf("Punkte: %d\n\n\n" , punkte);
    	if(punkte>abc[5].punkte){
    		abc[5].punkte=punkte; /*letztes element überschreiben*/   
    		abc[5].name=nome;     /*da neuer Highscore-Punktestand*/
    	}
    }
    
    void sortieren(void){/*neuer Wert wird, falls höher,richtig einsortiert*/
    	struct highscore temp;
    	int i;
    	int j=0;
    	while(j<10)
        {
            for(i=0; i<5; i++)
            {
    
                if(abc[i+1].punkte>abc[i].punkte)
                {
                    temp=abc[i+1];
                    abc[i+1]=abc[i];
                    abc[i]=temp;
    
                }
    
            }
        j++;
        }
    
    }
    
    void speichern(void){
    	FILE *smth=fopen("Highscoreliste.txt", "w");
    	if((smth = fopen ("Highscoreliste.txt", "w")) == NULL){
    		exit(1);
    	}
    	int i;
    	for(i=0; i<6; i++){
    		fprintf(smth, "%s\n %d\n" , abc[i].name , abc[i].punkte );
    	}
    
    	fclose(smth);
    
    }
    


  • Vllt hängt's ja wo anders? Denk aber das sollte alles richtig sein^^
    Zumindest bringt es keine Fehlermeldung.

    Bin in Eile:

    int scannen( struct highscore *abc[]){
       FILE *smth=fopen("Highscoreliste.txt", "a+");
        if((smth == NULL){
            return 1; // fehler, datei konnte nicht geöffnet werden
        }
        int i;
        for ( i=0; i<6; i++){
            fscanf(smth, "%s\n" , abc[i].name);
            fscanf(smth, "%d\n" , &abc[i].punkte);
        }
        fclose(smth);
        return 0; // alles war erfolgreich
    }
    

    Kann mir jmd sagen, welchen Wert ich dann unten in der Mainfunktion eingeben muss.
    Dank (void) ist dort auch scannen(); leer,
    aber bei int scannen( struct highscore *abc[]) ...?

    (Nutze C erst seit 1-2Wochen)



  • Hmm, das führt zu neuen Fehlern. 😃

    error: request for member 'name' in something not a structure or union.

    gleiches für 'punkte' .



  • Du kannst es dir um einiges einfacher machen, wenn du für Spielernamen anstelle eines char* ein Array benutzt.

    Anstelle den Dateinamen per "Highscoreliste.txt" im Code festzubrennen ist es besser, wenn du ihn als Parameter übergibst.
    Das macht den Code flexibler und wartungsfreundlicher.

    #define HIGHSCORE_ENTRIES_MAX 10
    #define NAMELEN_MAX 15
    
    typedef struct tagHighscoreList
    {
        char name [ NAMELEN_MAX + 1 ];
        unsigned score;
    } highscore_list;
    
    // Vorschlag für den Rückgabewert: 
    // Es wird die Anzahl der Einträge in der Highscorelist zurückgegeben.
    // Kann die Datei nicht gelesen werden, wird -1 zurückgegeben.
    int read_highscorelist ( const char* filename, highscore_list* hlist );
    
    int main(void)
    {
        highscore_list hlist [ HIGHSCORE_ENTRIES_MAX ] = {0};
        char* filename = "highscore.txt";
        int n = read_highscorelist ( filename, hlist );
    	...
    }
    


  • Ich glaub nicht, dass das mit dem statischen Array bei Structs funktioniert....

    Hier ein modifizierter Code: (kompiliert fehlerfrei mit gcc -Wall -pedantic unter cygwin)

    #include <stdio.h>
    #include <stdlib.h> /* manuelle Speicherverwaltung */ 
    
    typedef struct sHIGHSCORE{
    char name[10];		/* Maximale Länge eines Namens.  */ 
    int punkte;
    }HIGHSCORE;			/* Typedef für mehr Übersichtlichkeit */ 
    
    int scannen(HIGHSCORE *abc) {
        FILE *smth;
    	int i=0;
        if((smth=fopen("Highscoreliste.txt", "r")) == NULL) return -1; 		/* File konnte nicht geöffnet werden */ 		
        while(fscanf(smth,"%s %d", abc[i].name, &abc[i].punkte)==2)	i++;
        fclose(smth);
        return i; 		/* Rückgabewert: Anzahl der Namen auf der Liste */ 	
    }
    
    int main( int argc, char **argv) {
    	int i;
    	int n=6; /* Anzahl der Namen auf der Liste. Könnte man in der ersten Zeile der Datei speichern. */ 
    	HIGHSCORE *abc=malloc(n*sizeof(HIGHSCORE));      /* Manuelle Speicherreservierung */ 
    
    	n=scannen(abc); 
    
    	/* Testausgabe */ 
    	for (i=0;i<6;i++) printf("%s %i \n",abc[i].name,abc[i].punkte); 
    	printf("Anzahl=%i",n); 
    	/* Testausgabe Ende */ 
    
    	free(abc);
    	return 0;
    }
    

    Ich sollte noch erwähnen, dass meine Highscoreliste testweise so aussieht (für fscanf:

    name1 98
    name2 90 
    name3 88
    name4 70
    name5 60
    name6 33
    


  • Lymogry schrieb:

    Ich glaub nicht, dass das mit dem statischen Array bei Structs funktioniert....

    Hier ein modifizierter Code: (kompiliert fehlerfrei mit gcc -Wall -pedantic unter cygwin)

    #include <stdio.h>
    #include <stdlib.h> /* manuelle Speicherverwaltung */ 
    
    typedef struct sHIGHSCORE{
    char name[10];		/* Maximale Länge eines Namens.  */ 
    int punkte;
    }HIGHSCORE;			/* Typedef für mehr Übersichtlichkeit */ 
    
    int scannen(HIGHSCORE *abc) {
        FILE *smth;
    	int i=0;
        if((smth=fopen("Highscoreliste.txt", "r")) == NULL) return -1; 		/* File konnte nicht geöffnet werden */ 		
        while(fscanf(smth,"%s %d", abc[i].name, &abc[i].punkte)==2)	i++;
        fclose(smth);
        return i; 		/* Rückgabewert: Anzahl der Namen auf der Liste */ 	
    }
    
    int main( int argc, char **argv) {
    	int i;
    	int n=6; /* Anzahl der Namen auf der Liste. Könnte man in der ersten Zeile der Datei speichern. */ 
    	HIGHSCORE *abc=malloc(n*sizeof(HIGHSCORE));      /* Manuelle Speicherreservierung */ 
    
    	n=scannen(abc); 
    	
    	/* Testausgabe */ 
    	for (i=0;i<6;i++) printf("%s %i \n",abc[i].name,abc[i].punkte); 
    	printf("Anzahl=%i",n); 
    	/* Testausgabe Ende */ 
    	
    	free(abc);
    	return 0;
    }
    

    Ich sollte noch erwähnen, dass meine Highscoreliste testweise so aussieht (für fscanf:

    name1 98
    name2 90 
    name3 88
    name4 70
    name5 60
    name6 33
    

    Habe das nun testweise ausprobiert, bzw. bei mir lediglich die entsprechenden Teile ausgetauscht, wobei ich mein struct nebenbei behalten habe um die anderen Funktionen nicht umschreiben zu müssen.
    Es geht immer noch nicht? Es wird nach wie vor nur ein Name in der Highscoreliste angezeigt und zwar immer der neuste.
    Des Weiteren verwirrt mich diese Zeile hier doch sehr:

    n=scannen(abc); ? 6=scannen(abc);??

    return i; /* Rückgabewert: Anzahl der Namen auf der Liste */
    und dann in der Mainfunktion: int i, direkt drunter aber n=6 mit dem Kommentar, dass das die Anzahl der Namen auf der Liste ist... ?



  • Lymogry schrieb:

    Ich glaub nicht, dass das mit dem statischen Array bei Structs funktioniert....

    Das Strukturarray lebt innerhalt des Gültigkeitsbereichs von main, warum sollte das nicht funktionieren?
    Das es funktioniert, glaube ich für dich mit.
    Btw. wenn man davon ausgeht, dass die maximale Anzahl der Einträge in einer Highscoreliste konstant ist,
    wozu mit malloc arbeiten?

    Lymogry schrieb:

    Hier ein modifizierter Code: (kompiliert fehlerfrei mit gcc -Wall -pedantic unter cygwin)

    Was bitte ist daran modifiziert?!
    'Modifiziert' allenfalls für potentielle Pufferüberläufe und segmentation faults.
    In der Funktion scannen kann i > 5 werden und fscanf kann Namen mit mehr als 9 Zeichen einlesen.

    Utakata schrieb:

    struct highscore{
        char *name;
        int punkte;
    }abc[6];
    

    Utakata schrieb:

    Habe das nun testweise ausprobiert, bzw. bei mir lediglich die entsprechenden Teile ausgetauscht,
    wobei ich mein struct nebenbei behalten habe um die anderen Funktionen nicht umschreiben zu müssen.

    Ah, toll! Dann gibts für die Namen also immer noch keinen Speicher! 👍
    -> Crash.

    Utakata schrieb:

    Des Weiteren verwirrt mich diese Zeile hier doch sehr:
    n=scannen(abc); ? 6=scannen(abc);??

    return i; /* Rückgabewert: Anzahl der Namen auf der Liste */
    und dann in der Mainfunktion: int i, direkt drunter aber n=6 mit dem Kommentar, dass das die Anzahl der Namen auf der Liste ist... ?

    Das ist Variablenrecycling.
    Man nutzt die vorteilhafte Eigenschaft von Variablen, verschiedene Werte zu verschiedenen Zeiten speichern zu können.
    Im ersten Schritt wird die Variable mit 6 initialisiert und für die Speicherallokation benutzt.
    Danach fungiert sie als Empfänger des Rückgabewertes der Funktion scannen.



  • Ah, toll! Dann gibts für die Namen also immer noch keinen Speicher! 👍
    -> Crash.

    Keinen Speicher? Inwiefern? Wie mach ich das denn dann? Muss bzw. kann ich meinen struct entfernen und würde es dann in der Tat funktionieren?

    Wobei ich anschließend nicht sicher wüsste, wie ich die anderen Funktionen umbaue und welche werte ich dann unten in der Main an die Funktionen weitergeben muss bzw. was ich in die Klammern schreiben muss bei z.Bsp. speichern(?);
    Einfach nur abc? X.x Eben probiert... -zig Fehlermeldungen.
    Mensch, muss ich denn unbedingt alles umbauen? Wenn ja, kann man es mir bitte möglichst einfach erklären? Wie gesagt, ich arbeite erst seit etwas über einer Woche mit C.

    Btw. wenn man davon ausgeht, dass die maximale Anzahl der Einträge in einer Highscoreliste konstant ist,
    wozu mit malloc arbeiten?

    Da es mir einen Fehler beseitigte und selbst keine Probleme zu bereiten scheint.



  • Utakata schrieb:

    Keinen Speicher? Inwiefern? Wie mach ich das denn dann?

    Indem du statt eines Zeigers ein Array für den Spielernamen benutzt.
    Weiteres entnehme dem C-Buch deines Vertrauens unter den Kapiteln Arrays, dynamische Speicherallokation.

    Utakata schrieb:

    Wobei ich anschließend nicht sicher wüsste, wie ich die anderen Funktionen umbaue und welche werte ich dann unten in der Main an die Funktionen weitergeben muss bzw. was ich in die Klammern schreiben muss bei z.Bsp. speichern(?);
    Einfach nur abc?

    Das wurde dir bereits von Lymogry gezeigt.
    Weiteres verrät dir das C-Buch deines Vertrauens unter den Kapiteln Zeiger, Parameterübergabe an Funktionen.

    Utakata schrieb:

    X.x Eben probiert... -zig Fehlermeldungen.

    Nach dem Trial and Error Zufallsprinzip zu lernen, ist nicht gerade eine effektive Methode, darum

    Utakata schrieb:

    Wie gesagt, ich arbeite erst seit etwas über einer Woche mit C.

    investiere lieber noch etwas mehr Zeit für die Grundlagen.



  • CJosef schrieb:

    Lymogry schrieb:

    Ich glaub nicht, dass das mit dem statischen Array bei Structs funktioniert....

    Das Strukturarray lebt innerhalt des Gültigkeitsbereichs von main, warum sollte das nicht funktionieren?
    Das es funktioniert, glaube ich für dich mit.
    Btw. wenn man davon ausgeht, dass die maximale Anzahl der Einträge in einer Highscoreliste konstant ist, wozu mit malloc arbeiten?

    Hast recht ... (Die Struct hat ja gar keine Pointer) Ja, es geht auch statisch.

    Hat dann aber immernoch das Problem, dass es eine fixe Größe hat. Ich würd mir die Highscoregröße mitspeichern und dann auslesen. Also doch malloc.

    Was bitte ist daran modifiziert?!
    'Modifiziert' allenfalls für potentielle Pufferüberläufe und segmentation faults.
    In der Funktion scannen kann i > 5 werden und fscanf kann Namen mit mehr als 9 Zeichen einlesen.

    Ja, aber das interessiert mich doch nicht 😉
    In meinem Kommentar steht schon, dass man die Länge irgendwo anders speichern und auslesen sollte. Dass da n=6 steht hab ich nur als fixen Wert für das Beispiel übernommen. Und die 10 Stellen für einen Namen sind auch nur platzhaltend drin. (Ich hab ihm nur ein funktionsfähiges Minimalbeispiel geschrieben)
    Utakata kann sich sicher darum bemühen, genügend Speicher für seine Liste zu reservieren.

    Modifiziert heißt nur, dass es leicht verändert wurde. Dein Vorschlag mit dem Rückgabewert ist zb drin. 😉



  • Langsam bekomme ich hier wirklich die Krise.
    Ich kann nicht mehr Zeit investieren, da es ein einwöchiger Kurs der Uni war und das Projekt bald fällig ist.

    Außerdem wollte ich nur eine andere Schreibweise oder Fehlerbehebung für:

    FILE*smth=fopen("Highscoreliste.txt", "r");
    if((smth = fopen ("Highscoreliste.txt", "r")) == NULL){
    FILE*smth=fopen("Highscoreliste.txt", "w");}
    

    Und keine andere Schreibweise für mein komplettes Programm, das funktioniert nämlich. 😞

    Ich werd mir jetzt nochmal all die Vorschläge (von denen ich inzwischen zugegebenerweise etwas verwirrt bin..) ansehen...



  • Lymogry schrieb:

    CJosef schrieb:

    Lymogry schrieb:

    Ich glaub nicht, dass das mit dem statischen Array bei Structs funktioniert....

    Das Strukturarray lebt innerhalt des Gültigkeitsbereichs von main, warum sollte das nicht funktionieren?
    Das es funktioniert, glaube ich für dich mit.
    Btw. wenn man davon ausgeht, dass die maximale Anzahl der Einträge in einer Highscoreliste konstant ist, wozu mit malloc arbeiten?

    Hast recht ... (Die Struct hat ja gar keine Pointer) Ja, es geht auch statisch.

    Hat dann aber immernoch das Problem, dass es eine fixe Größe hat. Ich würd mir die Highscoregröße mitspeichern und dann auslesen. Also doch malloc.

    Was bitte ist daran modifiziert?!
    'Modifiziert' allenfalls für potentielle Pufferüberläufe und segmentation faults.
    In der Funktion scannen kann i > 5 werden und fscanf kann Namen mit mehr als 9 Zeichen einlesen.

    Ja, aber das interessiert mich doch nicht 😉
    In meinem Kommentar steht schon, dass man die Länge irgendwo anders speichern und auslesen sollte. Dass da n=6 steht hab ich nur als fixen Wert für das Beispiel übernommen. Und die 10 Stellen für einen Namen sind auch nur platzhaltend drin. (Ich hab ihm nur ein funktionsfähiges Minimalbeispiel geschrieben)
    Utakata kann sich sicher darum bemühen, genügend Speicher für seine Liste zu reservieren.

    Modifiziert heißt nur, dass es leicht verändert wurde. Dein Vorschlag mit dem Rückgabewert ist zb drin. 😉

    Danke für die Antwort, gab mir gerade einen Hinweis, der evtl. einen kleinen Fehler im Programm begründen könnte.^^



  • Lymogry schrieb:

    Hat dann aber immernoch das Problem, dass es eine fixe Größe hat. Ich würd mir die Highscoregröße mitspeichern und dann auslesen. Also doch malloc.

    Meine Highscoreliste hat aber maximal 10 Einträge. Also doch kein malloc und kein Problem.
    Bätsch :p


Log in to reply