Hallo,
Ich schreibe gerade ein Programm, welches aus einer txt-Datei
Zeilenweise einen eingelesenen String (Namen) vergleicht und dann
ausgibt, ob der Name existiert oder nicht.
Hier mein Code:
1
#include<stdio.h>
2
#include<string.h>
3
#include<stdlib.h>
4
#include<limits.h>
5
6
intmain(void)
7
{
8
charcontent[80];
9
charname[20],name2[20];
10
inti=0;
11
intflag=0;
12
13
FILE*fp;
14
15
fp=fopen("Liste.txt","r");
16
17
if(fp==NULL)
18
{
19
printf("Datei konnte nicht geöffnet werden\n Vorgang abgebrochen\n");
20
fclose(fp);
21
exit(0);
22
}
23
24
else
25
{
26
printf("Datei wurde korrekt gelesen\n");
27
}
28
29
30
printf("Geben Sie den zu suchenden Namen ein\n");
31
scanf("%s",name);
32
33
34
for(i=0;i<20;i++)
35
{
36
fgets(content,255,fp);
37
sscanf(name,"%s",name2);
38
39
if(strcmp(name2,content)!=0)
40
{
41
flag=0;
42
}
43
44
else//if(strcmp(name2, content) == 0)
45
{
46
flag=1;
47
break;
48
}
49
}
50
51
printf("Vergleich beendet\n");
52
53
if(flag==0)printf("Der Name existiert NICHT in der Liste\n");
54
55
elseprintf("Der Name existiert in der Liste\n");
56
57
fclose(fp);
58
59
return0;
60
}
Die txt-Datei sind so aus:
Anton
Gustav
Karl
Heinrich
Tobias
Das Problem ist, dass in der txt-Datei das Return mit eingelesen wird.
Wie filtere ich dieses heraus?
Mit freundlichen Grüßen
Mit strrchr suchen und ggf. durch '\0' ersetzen.
oder
Selber suchen (for- oder while-Schleife)
oder
kein fgets sondern Zeilen mit fscanf und %s einlesen
Aber noch etwas anderes:
Weißt du wofür die 255 bei fgets(content, 255, fp); steht?
Und wie die mit content zusammen hängt?
Danke für die schnelle Antwort!
Ich habe den Fehler schon gefunden
statt
1
fgets(content,255,fp);
2
sscanf(name,"%s",name2);
sollte stehen
1
fgets(content,255,fp);
2
sscanf(content,"%s",name2);
Der String-Compare Befehl filtert sozusagen ja schon das Return heraus.
Zu deiner Frage:
255 ist die Große von content(?). Vorher war das content bei mir 255
statt 80 und hatte es vergessen im Befehl umzuändern.
Mit freundlichen Grüßen
Elvir Ègalo schrieb:> Vorher war das content bei mir 255 statt 80 und hatte es vergessen im> Befehl umzuändern.
Und was lernst du daraus?
Um's abzukürzen: Du solltest daraus lernen, daß es nie gut ist, solche
Zahlen mehrfahch irgendwo hinzuschreiben. Was meinst du, was bei einem
wirklich komplexen Programm passiert, wenn man da mal so eine Größe
ändert?
Besser ist es, die Größe genau einmal zu definieren:
1
#define CONTENT_SIZE 255
2
3
[...]
4
5
{
6
charcontent[CONTENT_SIZE];
7
8
[...]
9
10
fgets(content,CONTENT_SIZE,fp);
So kann es nicht passieren, daß die Werte aufgrund einer Änderung
irgendwann nicht mehr zusammenpassen.
Elvir Ègalo schrieb:> Der String-Compare Befehl filtert sozusagen ja schon das Return heraus.
Nein.
Das mach in diesem Fall das sscanf.
\n ist ein Whitespace und da hört sscanf bei %s mit dem Einlesen auf.
Bzw. überliest es am Anfang.
ist im übrigen auch keine gute Idee.
Gemeint sind die 20 in der for-Schleife.
Woher weißt du, dass in der Datei 20 Namen stehen? Was ist, wenn da mal
mehr oder weniger Namen enthalten sind?
Fazit: Anstatt einer for-Schleife, geht man anders vor.
Alle Datei-Leseoperationen in C sind so gestaltet, dass man ihren Return
Wert in der einen oder anderen Form dazu benutzen kann um eine Antwort
auf die Frage zu erhalten: konnte von der Datei (noch) gelesen werden
oder nicht?
D.h. man wird die notwendige Schleife so gestalten, dass sie genau über
diesen Return Wert gesteuert wird. Wenn gelesen werden konnte, dann
erfolgt ein weiterer Durchgang durch die Schleife.
Bei fgets sieht die Sache so aus, dass fgets einen von NULL
verschiedenen Wert liefert, wenn gelesen werden konnte und den Wert NULL
wenn nicht gelesen werden konnte. Die Schleife sieht dann so aus
1
...
2
3
while(fgets(content,CONTENT_SIZE,fp)!=NULL)
4
{
5
sscanf(content,"%s",name2);
6
....
7
8
}
Wenn man es ganz genau nimmt, dann müsste man nach Beendigung dieser
while Schleife noch prüfen, warum diese Schleife abgebrochen wurde,
warum also fgets nicht mehr lesen konnte. Denn da gibt es ja mehrere
Möglichkeiten. Eine davon ist, dass die Datei komplett verarbeitet
wurde, man also bis zum EOF (End Of File) gelesen hat. Ein Aufruf der
feof()-Funktion klärt das. Liefert er TRUE, dann ist alles in Ordnung.
Liefert der aber nicht TRUE, dann gab es einen Fehler. Zb. weil jemand
den USB Stick abgezogen hat, oder die CD einen Lesefehler hatte, oder
die Netzwerkverbindung zusammengebrochen ist, oder ... Da gibt es viele
Möglichkeiten, warum fgets den Versuch von einer Datei zu lesen
abbrechen musste - EOF ist nur eine davon.
printf("Datei konnte nicht geöffnet werden\n Vorgang abgebrochen\n");
6
fclose(fp);
7
exit(0);
8
}
Wenn Dir fopen einen NULL-Pointer zurückgibt und Du anschließend
versuchst, diesen Pointer mit fclose zu schließen, so könnte Dein
Programm mit einer segmentation violation abbrechen, wahrscheinlich
sogar, bevor Du eine Chance hast, die vorhergehende Fehlermeldung zu
sehen. Denn die geht nach stdout, stdout ist gepuffert und Puffer werden
bei einem Abbruch meistens nicht mehr geflusht (siehe man fflush). Also,
schicke Deine Fehlermeldungen mit fprintf nach stderr, dort gehören sie
hin und es reduziert die Gefahr, dass Dir Meldungen verloren gehen. Vor
allem aber verzichte auf das fclose an dieser Stelle, es ist mindestens
konzeptionell falsch. Es kann sein, dass fclose diesen Fehler abfängt,
das glaube ich aber nicht.
ah8 schrieb:> Also, schicke Deine Fehlermeldungen mit fprintf nach stderr, dort gehören> sie hin und es reduziert die Gefahr, dass Dir Meldungen verloren gehen.
Und am besten auch gleich noch eine etwas genauere Meldung. Eine
Fehlermeldung liefert strerror(errno) zurück. Für alles zusammen (also
die Fehleremeldung plus eigenen Text nach stderr schreiben) gibt's auch
schon die Funktion perror():
1
if(fp==NULL)
2
{
3
perror("Datei konnte nicht geöffnet werden");
4
exit(0);
5
}
Dann wird dein Text ausgegeben, gefolgt von einem Doppelpunkt und dem
Grund, warum die Datei nicht geöffnet werden konnte.
Und wenn man noch ganz lieb ist, dann führt man in der Fehlermeldung
auch noch an, wie die Datei heißt, die nicht geöffnet werden konnte.
Microsoft hat Millionen Programmierer mit ihrer generischen Meldung "DLL
konnte nicht geöffnet werden" in die Weißglut getrieben, weil kein
Mensch wusste, von welcher DLL eigentlich die Rede war. Das ist
insbesondere dann frustrierend, wenn du einem Kunden am Telefon weiter
helfen sollst, und der hat nicht mehr als diese Meldung.
Karl Heinz schrieb:> Und wenn man noch ganz lieb ist, dann führt man in der Fehlermeldung> auch noch an, wie die Datei heißt, die nicht geöffnet werden konnte.
... und nicht nur den Namen sondern mit voller Pfadangabe.
> Microsoft hat Millionen Programmierer mit ihrer generischen Meldung "DLL> konnte nicht geöffnet werden" in die Weißglut getrieben ...
Dafür gibt es jetzt beim Abdocken eines "USB-Massenspeichergerätes" die
in ihrer Präzision kaum zu übertreffende Meldung: "Dieses Gerät wird
gerade verwendet. Schließen Sie alle Programme oder Fenster, die
möglicherweise das Gerät verwenden, und wiederholen Sie den Vorgang"
Wolfgang schrieb:> Dafür gibt es jetzt beim Abdocken eines "USB-Massenspeichergerätes" die> in ihrer Präzision kaum zu übertreffende Meldung: "Dieses Gerät wird> gerade verwendet. Schließen Sie alle Programme oder Fenster, die> möglicherweise das Gerät verwenden, und wiederholen Sie den Vorgang"
Eigentlich unglaublich, aber früher war das doch noch schlechter. Da
wurde nur gemeldet, daß das Gerät gerade nicht beendet werden kann,
und man soll es doch später nochmal versuchen. Einfach überhaupt kein
Hinweis darauf, daß es daran liegen könnte, daß ein Programm noch eine
Datei auf dem Datenträger offen haben hat.
Meine Lieblingsmeldung aus Lotus Notes:
"Beim Öffnen eines Fensters ist ein Fehler aufgetreten."
Passt zwar thematisch nicht ganz hier rein.
Aber meine liebste Fehlermeldung war mal, als ich mich mit einem
Lenovo-Notebook (Win7) nicht ins WLAN verbinden konnte:
"Die Problembehandlung konnte aufgrund eines Problems nicht gestartet
werden."
Den Programmierer hätte ich wirklich gerne mal kennengelernt :)
(Hab ich mir sogar aufgehoben)