C Strings aus Datei einlesen, vergleichen und Zählen
-
Hallo ich schreibe gerade in C ein Programm, welches eine Textdatei mit folgendem Inhalt verarbeiten soll:
1960;Frankreich; Sowjetunion 1964;Spanien;Spanien 1968;Italien;Italien 1972;Belgien;Deutschland 1976;Jugoslawien;Tscheslowakei 1980;Italien;Deutschland 1984;Frankreich;Frankreich 1988;Deutschland;Niederlande 1992;Schweden;Dänemark 1996;England;Deutschland 2000;Belgien-Niederlande;Frankreich 2004;Portugal;Griechenland 2008;Österreich Schweiz;Spanien 2012;Polen-Ukraine;Spanien
Bisher kann mein Programm die gesamte Textdatei ausgeben und Jahr, Gastgeber und Sieger trennen.
Hier das Programm:#include <stdio.h> #include <conio.h> void txt_ausgeben(void){ int x, y; FILE *fp; fp = fopen("EM.txt", "r+"); while ((x = getc(fp, stdin)) != EOF){ putc(x, stdout); } fclose(fp); } int main(void){ int x, z=0, y, jahr; char gastgeber[150]; txt_ausgeben(); FILE *fp; fp = fopen("EM.txt", "r"); for (y = 0; y < 14; y++){ printf("Jahr:"); while ((x = getc(fp)) != ';'){ putc(x, stdout); } printf("\tGastgeber: "); while ((x = getc(fp, stdin)) != ';'){ putc(x, stdout); /*gastgeber[z] = x; z++;*/ } printf("\tSieger: "); while ((x = getc(fp, stdin)) != '\n'){ putc(x, stdout); } printf("\n"); } /*for (x = 0; x < z; x++){ printf("%c", gastgeber[x]); }*/ _getch(); }
Doch nun möchte ich noch ermitteln können welches Land die EM am häufigsten ausgetragen und welches am häufigsten Europameister geworden ist.
Ich bin Programmieranfänger und weiß nicht wie ich dies anstellen soll. Kann ich, wenn ich je ein String für die Gastgeber und die Europameister mache, die dann so vergleichen, dass ich die vorgekommenen Nationen zählen? Der Kommentar in meinem Programm ist der Versuch dafür nur ich weiß nicht wie ich die Nationen dann in dem Array vergleichen soll.
Wäre schön wenn einer von Euch einen Tipp für mich hätte, ich erwarte ja auch garnicht, dass mir hier ein fertiges Programm hingeworfen wird ich wüsste nur gerne eine Vorgehensweise oder einen Befehl mit dem ich das machen kann.
Danke im Voraus.
-
Du brauchst ein Stringarray je für Gastgeber+Europameister;
die befüllst du beim Auswerten der Datei und berechnest anschließend in Stringarrays das Maximum.
Ein Stringarray könnte z.B. so aussehenchar gastgeber[100][80]; /* max. 100 Strings mit max. 79 Zeichen Länge */ char emeister[100][80]; /* max. 100 Strings mit max. 79 Zeichen Länge */
Benutze zum Durchlauf der Datei Stringfunktionen, das zeichenweise zu machen, ist Unsinn.
Deine Funktion 'txt_ausgeben' ist Müll.
-
Was sagt denn dein Compiler zu den Zeilen 9, 30 und 36?
Er sollte da Warnungen ausspucken. (Wenn nicht, ändere das so, das du Warnungen bekommst)
-
@DirkB: Ja, er gibt Warnungen aus. 'Zu viele zu übergebende Parameter'
@Wutz: Ist der Hinweis darauf, dass Zeichenweise einzulesen ist, nur auf die Funktion bezogen oder auf den gesamten Code?
-
Dominik97 schrieb:
@DirkB: Ja, er gibt Warnungen aus. 'Zu viele zu übergebende Parameter'
Dann beheb den Grund für die Warnung.
Ne, nicht nötig,denn:
Dominik97 schrieb:
@Wutz: Ist der Hinweis darauf, dass Zeichenweise einzulesen ist, nur auf die Funktion bezogen oder auf den gesamten Code?
Für den ganzen Code.
Die Standardbibliothek hat extra ein paar Funktionen, die einem sowas abnehmen.
-
Danke DirkB, habe die stdin's entfernt nun kommen dort auch keine Befehle mehr.
Könntest du mich denn bitte auf die Funktionen nennen, die du meinst
-
Natürlich Warnungen und nicht Befehle
-
Die Funktione zum einlesen, die in
stdio.h
deklariert sind. MEist mit einem f vorne dran, da du ja aus einer Datei (file) liest.Und die eingelesenen Daten kannst du mit den Funktionen aus
string.h
verarbeiten.Einen Überblick findest du z.B. bei http://www.cplusplus.com/reference/clibrary/
-
Sorry Leute ich weiß nicht genau, was ihr von mir wollt. Zeilenweise einlesen mit fgets oder sscanf? Ich war eigentlich schon froh das es so funktioniert, wie ich es jetzt habe, gerade wegen den Trennzeichen. Vielleicht kann mir ja jemand ein kleines Codebeispiel geben.
Des weiteren habe ich die Nationen jetzt in ein mehrdimensionales Array gepackt, aber auch da bin ich mir nicht so sicher ob ihr das meintet. Ich könnte noch ein paar Ratschläge oder Beispiele gebrauchen.
Hier mal mein leicht abgeändertes Programm
#include <stdio.h> #include <conio.h> int main(void){ int x, z=0, y; char gastgeber[100][80],emeister [100][80]; FILE *fp; fp = fopen("EM.txt", "r+"); while ((x = getc(fp)) != EOF){ putc(x, stdout); } fclose(fp); fp = fopen("EM.txt", "r+"); for (y = 0; y < 14; y++){ printf("Jahr:"); while ((x = getc(fp)) != ';'){ putc(x, stdout); } printf("\tGastgeber: "); z = 0; while ((x = getc(fp)) != ';'){ putc(x, stdout); gastgeber[y][z] = x; z++; } gastgeber[y][z] = '\0'; printf("\tSieger: "); z = 0; while ((x = getc(fp)) != '\n'){ putc(x, stdout); emeister[y][z] = x; z++; } printf("\n"); } /*for (x = 0; x < 14; x++){ z = 0; while (gastgeber [x][z]!= '\0'){ printf("%c", gastgeber[x][z]); z++; } }*/ fclose(fp); _getch(); }
-
Zeilenweise einlesen get mit fgets. Formatiertes Einlesen geht mit (f)scanf. Da du hier eine formatierte Eingabe vorliegen hast, bietet sich daher scanf an:
int jahr; char gastgeber[1000]; char meister[1000]; scanf("%d ; %999[^;]; %999[^\n]", &jahr, &gastgeber, &meister);
(Code ist ungetestet)
Erklärung:
%d
: Liest Integer in Dezimaldarstellung, sollte bekannt sein.' '
: Ein Leerzeichen überliest eine beliebige Anzahl beliebigen Whitespace.;
: Ein Semikolon liest genau ein Semikolon. Ebenso geht das mit allen anderen Zeichen ohne Sonderbedeutung.%999[^;]
:%[]
liest eine Zeichenkette nur aus den Zeichen innerhalb der []. Mit ^ dreht man es um und liest alle Zeichen außer den angegebenen. 999 ist eine Angabe der Maximallänge. Hier werden also maximal 999 Zeichen gelesen, die kein ';' sind. Folglich bricht die Leseaktion bei Erreichen eines Semikolons ab.%999[^\n]
: Das gleiche, aber mit einem Zeilenumbruch ('\n'
).
Mit dem Rückgabewert von scanf kann man überprüfen, ob erfolgreich 3 Felder gelesen wurden.
-
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. Dasfscanf
läßt aber das '\n' (Zeilenende) im Eingabestrom stehen.
Das liest dann dasfgets
vomwhile
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?
-
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
oderb == 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 und3 = 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.
-
DirkB schrieb:
Einig schreiben die Konstanten immer nach vorne, damit bei einem einfachen = ein Fehler gemeldet wird.
Das ist dann eine Zuweisung und3 = 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.
Einestruct
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(); }