Externe Datei erstellen/lesen



  • 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



  • CJosef schrieb:

    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

    Hauptsache du bist glücklich. ^^



  • Utakata schrieb:

    Des Weiteren verwirrt mich diese Zeile hier doch sehr:

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

    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... ?

    Mit einem Gleichheitszeichen wird einer Variable immer der Wert auf der rechten Seite zugewiesen. Das kommt dem mathematischen n:=f(abc) gleich. Nicht umgekehrt. Will man in C logische Gleichheit prüfen, muss man n==f(abc) schreiben.

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

    Er meint, dass in der Struct nur ein char* steht, aber kein char name[10], was einen Speicher für 10 Buchstaben reserviert. In einem char* ist nur Platz für einen Pointer.
    Du musst deine Struct also verändern, du kannst gerne meine nehmen, aber keine Sorge, danach muss du keine Fkt umschreiben. Nur jedes deiner struct highscore mit einem HIGHSCORE ersetzen.
    Das Typedef erlaubt es dir, für struct sHIGHSCORE einen neuen kürzeren Namen zu definieren, also HIGHSCORE. Ist einfach übersichtlicher.

    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.

    Du schreibst dir oben deine Funktion z.b. int scannen(HIGHSCORE abc);
    Damit gibst du an, dass deine Funktion scannen eine Integerzahl zurück gibt. Das hab ich in meinem Beispiel mit n=scannen(abc) abgefangen und dann ausgegeben.
    In den Klammern steht, welche Variablen die Funktion erwarten muss. Bei mir steht ein HIGHSCORE
    Element. Das heißt, die Funktion kann einen Pointer auf einen Datentyp HIGHSCORE erwarten.
    Genau das musst du in der main in die Fkt reinschreiben.
    Also scannen(abc), da HIGHSCORE *abc definiert wird. Das Sternchen in der Typdefinition gibt an, welches Dereferenzierungslevel du hast, das heißt, wieviele Pointer du im Speicher durchlaufen musst, um an den Wert des Datentyps zu kommen. Wenn du hinterher nur abc aufrufst, bekommst du den Pointer mit einem Level. Den Eintrag bekommst du mit *abc, das Sternchen derefenziert dann. Wenn du abc[i] aufrufst, bekommst du den derefenzierten Datentypeintrag an i-ter Stelle. Die eckigen Klammern dereferenzieren automatisch!
    Die Funktion scannen(HIGHSCORE *abc) erwartet also einen Pointer mit Deferenzierungslevel 1 und abc hat das, also kommt in der main Fkt nur abc in die Klammern.

    ... Ein gutes Buch/Script kann das sicher besser erklären. 😉


Anmelden zum Antworten