C Strings aus Datei einlesen, vergleichen und Zählen



  • Dominik97 schrieb:

    Ich war eigentlich schon froh das es so funktioniert, wie ich es jetzt habe, gerade wegen den Trennzeichen.

    Wenn du schon so etwas machst und das auch noch mehr als zweimal schreiben musst, dann mache eine Funktion daraus.

    Benutze sprechende Variablennamen.
    x, y, z sind in einem Koordinatensystem ok.
    i, j, k als Zählvariablen auch.

    Aber für dich wäre zeichen, spalte, zeile besser.

    Das + im Mode von fopen brauchst du nicht.



  • Erst einmal möchte ich mich bei euch allen für die hilfreichen Tipps bedanken.
    Heute bin ich endlich dazu gekommen meinen Code zu bearbeiten.

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void){
    	int x, z = 0, y, jahr;
    	char gastgeber[1000], emeister[1000], puffer[200], line[1999],c;
    
    	FILE *fp;
    	fp = fopen("EM.txt", "r");
    
    	while (fgets(puffer, 50, fp))
    		fputs(puffer, stdout);
    	fclose(fp);
    
    	fp = fopen("EM.txt", "r");
    	printf("\n\n");
    
    		while (fgets(line, 200, fp)){
    			fscanf(fp, "%d; %999[^;];%999[^\n]", &jahr, &gastgeber, &emeister);
    			printf("Jahr: %d, Gastgeber: %s, Europameiser: %s\n", jahr, gastgeber, emeister);
    		}
    
    	fclose(fp);
    	_getch();
    }
    

    Doch es tun sich in der getrennten Ausgabe von Jahr, Meister und Gastgeber auf:
    Die erste Zeile (1960) wird nicht angezeigt wenn ich in der txt nicht am Anfang direkt eine neue Zeile beginne. Des weiteren wird die letzte Zeile doppelt ausgegeben. Was kann man dagegen machen?



  • In deiner zweiten Schleife liest das fgets schon eine Zeile ein.

    Die ist dann für das fscanf nicht mehr da. Das fscanf läßt aber das '\n' (Zeilenende) im Eingabestrom stehen.
    Das liest dann das fgets vom while ein.

    So sollte es klappen:

    while (3 == fscanf(fp, "%d; %999[^;];%999[^\n]", &jahr, gastgeber, emeister)) { //  der Adressoperator ist bei Arrays nicht nötig.
                printf("Jahr: %d, Gastgeber: %s, Europameiser: %s\n", jahr, gastgeber, emeister);
            }
    


  • Oh, Danke das direkt ins while zu schreiben macht ja auch Sinn.
    Könntest du mir trotzdem mal näher erklären was das 3== macht?


  • Mod

    Dominik97 schrieb:

    Könntest du mir trotzdem mal näher erklären was das 3== macht?

    Es vergleicht mit 3.

    Vielleicht solltest du mal nachschlagen, was (f)scanf genau macht und was es für Rückgabewerte hat. Das wäre eigentlich das erste was man tun sollte, wenn man gesagt bekommt, dass man eine unbekannte Funktion antrifft.



  • Dominik97 schrieb:

    Könntest du mir trotzdem mal näher erklären was das 3== macht?

    Du kannst a == b oder b == a schreiben.
    Und ob a und/oder b Konstanten sind spielt keine Rolle.

    Die 3 steht vorne, damit man sie nicht übersieht.

    Einig schreiben die Konstanten immer nach vorne, damit bei einem einfachen = ein Fehler gemeldet wird.
    Das ist dann eine Zuweisung und 3 = b geht nicht.

    SeppJ schrieb:

    Vielleicht solltest du mal nachschlagen, was (f)scanf genau macht und was es für Rückgabewerte hat.

    Das kannst du z.B. über den Link aus https://www.c-plusplus.net/forum/p2453639#2453639 machen.


  • Mod

    DirkB schrieb:

    Einig schreiben die Konstanten immer nach vorne, damit bei einem einfachen = ein Fehler gemeldet wird.
    Das ist dann eine Zuweisung und 3 = b geht nicht.

    Wobei wenn sieht es jemand, man sich anhören muss lassen, dass wie Yoda man programmiert.



  • SeppJ schrieb:

    Wobei wenn sieht es jemand, man sich anhören muss lassen, dass wie Yoda man programmiert.

    Das sagen die auf der anderen Seite.
    Und die ist "Schneller, leichter, verführerischer"



  • Danke DirkB für deine Hilfe 👍
    Eine letzte Frage bleibt mir allerdings noch: Wie kann ich denn nun Zähle wie oft wer Weltmeister oder Gastgeber war?



  • Damit du vergleichen kannst, brauchst du die Werte.
    Im Augenblick werden die alten Werte beim Einlesen aber überschrieben.

    Du musst also die Daten (in Variablen) merken.

    Du kannst ein 2D-Arry nehmen, so wie Wutz es schon in der ersten Antwort geschrieben hat.
    Eine struct wäre aber auch ganz praktisch.

    Wenn dir das mit Strings erstmal zu kompliziert ist, dann kannst du es ja erstmal mit Zahlen probieren.



  • Hallo noch einmal!

    Mein Programm läuft mittlerweile Dank eurer hilfreichen Tipps halbwegs zu meiner Zufriedenheit. Was ich jedoch noch nicht hinbekomme ist, dass die Länder nicht doppelt eingezählt werden um am Ende auch z.B ausgeben zu können, dass es zwei Rekordhalter gibt.
    Ich hoffe ihr könnt mir noch einmal dabei helfen!

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAX 30
    
    struct sieger {
    	char Land[MAX];
    	//int GG;
    	int EM;
    };
    
    int main(void){
    	struct sieger laender[50]; //Max 50 verschiedene EMs
    	int i,j, jahr, emeistermax=0,rekord;
    	char puffer[200], gastgeber[MAX], emeister[MAX], c;
    
    	FILE *fp;
    	fp = fopen("EM.txt", "r");
    
    	if (NULL == fp) {
    		printf("Konnte Datei \"EM.txt\" nicht öffnen!\n");
    	}
    	/*Da mir unklar ist, wie ich alle Europameister nicht doppelt einlese habe ich erst einmal die 'üblichen verdächtigen' eingefügt*/
    	strcpy(laender[0].Land, "Deutschland");
    	strcpy(laender[1].Land, "Spanien");
    	strcpy(laender[2].Land, "Frankreich");
    	strcpy(laender[3].Land, "England");
    	strcpy(laender[4].Land, "Italien");
    
    	while (fgets(puffer, 50, fp))
    		fputs(puffer, stdout);
    	fclose(fp);
    
    	fp = fopen("EM.txt", "r");
    	printf("\n\n");
    
    	//Von mir gesetzte Titel Null setzten um mit dem Feldern arbeiten zu können
    	for (i = 0; i <= 5; i++){
    		laender[i].EM = 0;
    	}
    
    	while (3 == fscanf(fp, "%d; %25[^;];%25[^\n]", &jahr, gastgeber, emeister)) { //  der Adressoperator ist bei Arrays nicht nötig. 
    		printf("Jahr: %d, Gastgeber: %s, Europameiser: %s\n", jahr, gastgeber, emeister);
    		for (i = 0; i <= 5; i++){
    			if (strcmp(laender[i].Land, emeister) == 0){
    				laender[i].EM++;
    			}
    		}
    		/*So hatte ich gehofft könnte es funktionieren, dass die Länder nicht doppelt ins struct kommen
    		for (x = 0; x <= 13; x++){
    			if (strcmp(emeister,laender[x].Land) != 0){
    				strcpy(laender[i].Land, emeister);
    				laender[i].EM = 0;
    			}
    		}
    		i++;*/
    	}
    
    	for (j = 0; j <= 4; j++){
    		printf("\nLand: %s, Siege: %i", laender[j].Land, laender[j].EM);
    	}
    
    	for (j = 0; j <= 4; j++){
    		if (laender[j].EM > emeistermax){
    			emeistermax = laender[j].EM;
    			rekord = j;
    		}
    	}
    	printf("\n\nDer Rekordmeister ist %s mit %i Siegen.", laender[rekord].Land, laender[rekord].EM); //Es können nicht mehrere Rekordmeister ausgegeben werden, daran muss ich auch noch arbeiten
    
    	fclose(fp);
    	_getch();
    }
    

  • Mod

    Du hast es doch schon fast. Jetzt lässt du eben die üblichen Verdächtigen weg, sondern guckst durch deine Liste durch, ob ein Name schon vorhanden ist, ansonsten fügst du ihn am Ende an.



  • Mein Problem ist ja, dass ich den Fehler in der for-Schleife nicht finde. Vielleicht könntest du mich über meinen Logik-Fehler aufklären.



  • Damit meine ich jetzt nur das einlesen der verschiedenen Länder. Mir ist klar das ich das vor dem Zählen der Titel machen müsste und das ich die variable i nicht benutzen könnte, das sie in der while-Schleife schon verwendet wird.
    Der Kommentar ist bloß meine Idee, die ich in einem anderen Programm nicht erfolgreich getestet habe.



  • Du machst zwar eine Kontrollausgabe deiner eingelesenen Daten (das ist gut), aber du kannst da nicht richtig erkennen, wie die Daten aussehen.

    printf("Jahr: %d, Gastgeber: <%s>, Europameister: <%s>\n", jahr, gastgeber, emeister);
    

    So kannst du auch eingelesene Leerzeichen erkennen.

    Die for-i Schleife (in der while-Schleife) brauchst du nicht.

    Und bei x brauchst du nur soweit zählen, soviel Länder du schon eingelesen hast:

    for (x = 0; x < i; x++){ // Das i habe ich wegen dem i++ genommen
    

    Du musst das i aber noch richtig vorbesetzen und auch im richtigen Moment erhöhen.



  • Ich bin mir nicht sicher ob ich Dich richtig verstanden habe.

    while (3 == fscanf(fp, "%d; %25[^;];%25[^\n]", &jahr, gastgeber, emeister)) { //  der Adressoperator ist bei Arrays nicht nötig. 
    		printf("Jahr: %d, Gastgeber: <%s>, Europameiser: <%s>\n", jahr, gastgeber, emeister);
    		i++;
    		for (x = 0; x < i; x++){
    			if (strcmp(emeister, laender[x].Land) != 0){
    				strcpy(laender[i-1].Land, emeister);
    				laender[i-1].EM = 0;
    			}
    			if (strcmp(laender[x].Land, emeister) == 0){
    				laender[i-1].EM++;
    			}
    		}		
    	}
    


  • Warum machst du erst i++ und dann beim Zugriff immer i-1 ?
    Da ist die Reihenfolge falsch.

    Du musst auch i nur erhöhen, wenn das Land noch nicht in der Liste war.

    (strcmp(emeister, laender[x].Land) != 0) ist das Gegenteil von (strcmp(laender[x].Land, emeister) == 0)
    Wenn das eine Wahr ist, ist das ander Unwahr und umgekehrt. Da reicht beim if ein else aus, kein neuer Vergleich.

    Und du musst erst die ganze Liste überprüfen, bevor du entscheiden kannst, dass das Land nicht vorhanden ist.
    Schau dir mal die C-Anweisung break an.


Anmelden zum Antworten