fehler mit strcpy beim Auslesen aus txt Dateien
-
Hallo Stockhausen,
Verwende auf jeden Fall std::string, so wie Dir schon geraten wurde.
struct person // eine Person { std::string name; int ordnungsnummer; std::string identifikation; };Und wenn Du Zahlen lesen möchtest, so lese auch Zahlen und keine Ziffern, die später interpretiert werden.
person p; datei >> p.ordnungsnummer;Mit getline kannst Du einen std::string bis zu einem bestimmten Zeichen ('"' oder '(') einlesen.
getline( datei, p.name, '(' );.. und wenn Du zwischendurch ein (druckbares) Zeichen überlesen möchtest, so kannst Du das mit
char dummy; datei >> dummy;und schließlich kann mit ignore alles bis zu einem bestimmten Zeichen (z.B. Zeilenende) überlesen werden.
Zusammengefasst:
person p; datei >> p.ordnungsnummer; char dummy; datei >> dummy; // '"' vor'm Namen überlesen getline( datei, p.name, '(' ); getline( datei, p.identifikation, ')' ); datei.ignore( 9999, '\n' ); // bis zum Zeilenende überlesenso könnte das Programm im Ganzen aussehen:
#include <iostream> #include <fstream> #include <string> #include <vector> #include <limits> // numeric_limits template< char C > std::istream& Char( std::istream& in ) { char c; if( in >> c && c != C ) in.setstate( std::ios_base::failbit ); return in; } std::istream& skipline( std::istream& in ) { return in.ignore( std::numeric_limits< std::streamsize >::max(), '\n' ); } struct person // eine Person { std::string name; int ordnungsnummer; std::string identifikation; }; // -- eine Person einlesen std::istream& operator>>( std::istream& in, person& p ) { // Format: <nr> "<--- Name -->(<----- identifikation ->) return getline( getline( in >> p.ordnungsnummer >> Char<'"'>, p.name, '(' ), p.identifikation, ')' ); } int main() { using namespace std; vector< person > personen; // viele Personen { ifstream datei("personen.txt"); if( !datei.is_open() ) { cerr << "Fehler beim Oeffnen der Datei" << endl; return -2; } for( person p; datei >> p; datei >> skipline ) personen.push_back( p ); } cout << personen.size() << " Eintraege gelesen" << endl; // mache was mit 'personen' cin.get(); return 0; }Oops - jetzt hat SeppJ auch schon geantwortet ..
Gruß
Werner
-
Hallo Seppj und Werner,
recht herzlichen Dank für die kompetente Hilfe! So sieht das natürlich auch schon viel übersichtlicher aus. Ich möchte im weiteren Verlauf des Programmes unter der Verwendung einer zweiten Textdatei bestimmte Verhältnisse zwischen den Personen in der Liste anzeigen lassen können. Da werde ich sicherlich nochmal die ein oder andere spezifische Frage hier äußern.
Grüße
Stockhausen
-
Hallo zusammen,
ich habe mal wieder etwas weiter gebastelt und stoße wieder mal auf Probleme. Auch wenn eure Lösungen natürlich wesentlich schicker sind als meine, habe ich basierend auf meinem Code weitergebastelt. Aber auch nun bekomme ich keine Ausgabe, obwohl der Compiler mir keinen Syntaxfehler angibt. Sieht jemand von euch das Problem?
Ich wäre schon voll auf zufrieden, wenn das Programm einfach laufen würde. Ich weiß, dass ihr wesentlich elegantere Lösung parat haben werdet, aber diese bringen mir nichts, wenn ich meinen eigenen Code noch nocht mal verstehe.
#include <iostream> using namespace std; #include <string.h> #include <stdlib.h> #include <fstream> struct personen { struct personen *naechster; char name[64]; int ordnungsnummer; char identifikation[64]; } ; enum zustand {imON,imNamen,imID}; struct personen *ladedaten(ifstream &datei); struct personen *ladeperson(ifstream &datei); int main() { struct personen *wurzel=NULL; ifstream datei; datei.open("personen.txt"); wurzel=ladedaten(datei); while(wurzel!=NULL) { cout << wurzel->name << " besitzt die " << wurzel->ordnungsnummer << "mit der Identifikation " << wurzel->identifikation << "." << endl; wurzel=wurzel->naechster; } } struct personen *ladedaten( ifstream &datei) { struct personen *wurzel=NULL, *jetzt, *neu; while(!datei.eof()) { neu=ladeperson(datei); if (neu!=NULL) { if (wurzel==NULL) wurzel=neu; else jetzt->naechster=neu; jetzt=neu; } } return wurzel; } struct personen *ladeperson( ifstream &datei) { struct personen *fest; char puffer[100],zeichen; int zaehler; enum zustand zustand; fest=new struct personen; fest->naechster=NULL; zustand=imON; zaehler=0; for (;;) { datei.get(zeichen); if (datei.eof()) break; switch(zeichen) { case '"': puffer[zaehler]='\0'; zaehler=0; fest->ordnungsnummer=atoi(puffer); zustand=imNamen; break; case '(': if (zustand!=imON) { puffer[zaehler]='\0'; zaehler=0; strcpy(fest->name,puffer); zustand=imID; } break; case ')': if (zustand!=imON) { puffer[zaehler]='\0'; zaehler=0; strcpy(fest->identifikation,puffer); } puffer[zaehler]='\0'; zaehler=0; break; default: puffer[zaehler]=zeichen; zaehler++; break; } } }
-
Warum benutzt du immer noch char-Arrays? Warum bastelst du selber eine Liste? Warum benutzt du C-Funktionen, deren Erfolg/Misserfolg man nicht in allen Fällen prüfen kann? Wieso versuchst du noch nicht einmal, dies zu prüfen? Wieso hast du dir nicht ein einziges der vielen Konzepte die dir gezeigt wurden mal angeguckt? Wieso hast du keinen einzigen der Tipps die dir gegeben wurden umgesetzt? Wieso hast du keinen einzigen der vielen Hinweise auf Fehler in deinem Programm befolgt? Wieso fügst du stattdessen noch Pointergefrickel als zusätzliche Fehlerquelle ein? Wieso nullst du sinnlos deine Zeiger und vertuscht so mögliche Fehler? Wieso nullst du deine Zeiger mit NULL, statt mit 0 oder nullptr? Wieso gibt es in deinem Programm zwar news, aber keine deletes? Wieso benutzt du keine Objekte, die sich selber verwalten (RAII)?
Irgendwie bist du selber Schuld, wenn das nicht läuft.
Ach ja: Dein ladeperson hat kein return, obwohl es einen Rückgabewert ungleich void hat. Das hätte dir dein Compiler auch gesagt, würdest du mal Warnungen anschalten.
-
Atme mal in eine Tüte... Wieso so gehässig? Es sind nicht alle Menschen auf der Welt so gewandt beim Programmieren, daher verwende ich eure Angaben nicht, weil ich Anfänger bin und eure Codes nicht verstehe und es gerne schrittweise erlernen möchte, aber dabei wohl lieber in Zukunft auf dieses Forum hier verzichten werde.
Mein Compiler gibt zu diesem Code keine Fehlermeldung aus, die ich sonst sehr gerne beherzigt hätte, aber der große SeppJ kann ja in die Zukunft sehen.
Ein einfacher Hinweis zu dem Fehler hätte es auch getan.
-
Stockhausen schrieb:
Atme mal in eine Tüte... Wieso so gehässig?
Weil das Problem eindeutig selbstgemacht ist. Und du weißt es besser, denn es wurde dir gleich mehrfach erklärt. Es muss ja nicht gleich alles überarbeitet werden, aber da wurde keine einzige Zeile korrigiert, sondern stattdessen noch mehr und noch größere Fehlerquellen hinzugefügt.
Stockhausen schrieb:
Atme mal in eine Tüte... Wieso so gehässig?
Weil viele Leute viel Arbeit investiert haben, um dir zu helfen und absolut nichts davon angekommen ist.
Mein Compiler gibt zu diesem Code keine Fehlermeldung aus, die ich sonst sehr gerne beherzigt hätte, aber der große SeppJ kann ja in die Zukunft sehen.
Deshalb auch der Hinweis, dass du die Warnungen einschalten sollst.
Ein einfacher Hinweis zu dem Fehler hätte es auch getan
Dein ganzes Programm ist so programmiert, das wird noch viele viele weitere Fehler erzeugen. Ich und alle anderen haben dir erklärt, wieso.
-
Ich habe mich mehrfach dafür bedankt, dass "viele Leute" - also Werner und Du zzgl. einige Tipps der weiteren User, mir ein ganz anderes Konzept dargelegt haben. Leider kann ich damit noch nichts anfangen, weil ich - wie ich bereits erwähnt habe - Anfänger bin. Dann tut es mir leid, da ihr viel Arbeit investiert habt. Wenn ich Klavier spielen lerne, versuche ich mich auch nicht an dem Presto Satz aus der Beethoven-Mondscheinsonate. Videonauth, ist derjenige der mich auf den Fehler hingewiesen hat, dass das Array nicht richtig definiert ist, das hilft mir weiter. Dieser Code ist nur als Lernschritt gedacht und da muss man eben Fehler machen. Ist mir schon klar, dass ist damit nicht die Computerlinguistik revolutioniere, aber ich hatte gehofft bei freundlichem spezifischen Fragen Unterstützung zu bekommen.
Ich kann es total verstehen, wenn ihr Geeks genervt seid und Leute hier ohne Eigeninitiative Komplettlösungen verlangen. Ich versuche mich da selbst durchzuarbeiten und der ein oder andere Hinweis hilft dann. Im Laufe der Zeit erreiche ich dann auch den Skill um eure wesentlich eleganteren Methoden, die genannt worden sind, anwenden zu können.
-
SeppJ vs Stockhausen aka der Jüngling im Feuerofen:
http://www.youtube.com/watch?v=3XfeWp2y1Lk
-
Vergleich (wegen der "Einfachheit")
Char arrays (das was du benutzt) vs std::string
char arrays: (kopieren)char a[100] = "Test"; // Dazu die Gefahr das dieser Buffer zu klein ist. char b[100]; strcpy(b, a);std::string: (kopieren)
std::string text = "Test"; std::string text2 = text; //Einfach =, std::string kümmert sich automatisch um die richtige Größe des Buffers und erweitert diesen auch bei Bedarf.Handgemachte Liste vs std::vector
Mit Handgemachter Listestruct personen { struct personen *naechster; char name[64]; int ordnungsnummer; char identifikation[64]; } ; personen * p = new personen; // Du musst dich um die Freigabe kümmern. p->naechster = new personen; // Einfügen, auch dieser Speicher muss Freigegeben werden. p->naechster->naechster = NULL;Mit std::vector (und std::string)
struct Person { std::string name; int ordnungsnummer; std::string id; }; std::vector<Person> p; Person neu; // Dieses Objekt wurde nicht mit new angelegt, sondern wurde direkt auf dem Stack erstellt. Das ist a) schneller und b) brauchst du dich nicht um die Freigabe kümmern. neu.name = "Hello"; neu.ordnungsnummer = 1; neu.id = 3; p.push_back(neu); // Einfügen p.push_back(neu); // Und gleich nochmal. std::vector kümmert sich automatisch um die richtige Größe des BuffersWas ist davon nun einfacher? Die handgemachten Sachen, oder die ganzen Hilfsmittel, die dir viel Arbeit abnehmen? Willst du wirklich darauf verzichten?
-
Stockhausen schrieb:
Wenn ich Klavier spielen lerne, versuche ich mich auch nicht an dem Presto Satz aus der Beethoven-Mondscheinsonate.
Und da liegt das Problem: Du baust dir gerade ein Klavier...
-
Hallo Stockhausen,
ich kann den Frust von SeppJ verstehen, mir geht es ja ähnlich, obwohl ich solche Situationen inzwischen mehr mit einem lachenden denn mit einem weinenden Auge hinnehme. Ich akzeptiere aber auch Deinen Wunsch wissen zu wollen, warum Dein Programm nicht funktioniert.
Ganz vordergründig geht es in der Funktion ladeperson schief, weil Du hier ohne Zustandskontrolle (Variable zustand) auf ein '"' reagierst, welches aber pro Zeile mehr als einmal vorkommt.
Ein einfacher Hack dieses Fehlers (Fehlerbehebung wäre vermessen) besteht darin, hinter der Zeile 97 noch folgendes einzufügen:strcpy(fest->identifikation,puffer); // Zeile 97 datei.ignore( 9999 /*maximal so viel Zeichen*/, '\n' ); // <-- neu return fest; // <-- neuda identifikation, der letzte Member ist, der gelesen ist, so wird anschließend einfach der Rest der Zeile ignoriert, und dann die Funktion verlassen. Mit der Datei, die Du hier gepostete hast, funktioniert das dann.
Zeile 97 ist übrigens eine sehr interessante Stelle. Genau hier wäre es nämlich möglich, mit einer wohl präperierten Datei 'personen.txt' den PC zu kapern, auf dem dieses Programm läuft. Wenn die Benutzerrechte reichen, kann ein eingeschleustes Programm hier alles machen, was ein Programm auf einem PC machen kann - vom Versenden von tausenden von SPAM-Mails mit Deinem Account als Absender bis zum Formatieren der Festplatte.
arghonaut schrieb:
Stockhausen schrieb:
Wenn ich Klavier spielen lerne, versuche ich mich auch nicht an dem Presto Satz aus der Beethoven-Mondscheinsonate.
Und da liegt das Problem: Du baust dir gerade ein Klavier...
das war auch mein Gedanken, bevor ich die Beiträge dazu gelesen habe!
Stockhausen- es ist Dir sicher nicht bewusst - aber Du versuchst tatsächlich, Dir die Funktionen zusammen zu bauen, die es schon gibt und mit denen Du spielen kannst, wenn man es denn kann.
Vielleicht ein Anfang: Gebe den Membern name und identifikation den Typ std::string. Du benötigst dann noch ein #include <string>. person wird dann zu
struct personen { struct personen *naechster; std::string name; int ordnungsnummer; std::string identifikation; } ;Anschließend musst Du die Zeilen 88 und 97 anpassen:
fest->name = puffer; // vorher: strcpy(fest->name,puffer); .... fest->identifikation = puffer; // vorher: strcpy(fest->identifikation,puffer);Dann kannst Du auch auf das #include <string.h> verzichten.
Gruß
Werner
-
Hey,
danke für die weiteren Vorschläge! Ich werde mich damit näher befassen, doch im Moment komme ich noch nicht dazu.
grüße
Stockhausen
-
Hallo Zusammen,
ich habe mich auch mal an der Aufgabe versucht, doch leider funktioniert sie noch nicht ganz. Ich habe mich darum bemüht, die Ratschläge zu befolgen, aber ich bin auch nur eine Anfängerin...
Mir ist zwar bewusst, dass der Beitrag schon was länger her ist, aber ich dachte, ich versuche mal mein Glück
#include <iostream> using namespace std; #include <string> #include <stdlib.h> #include <fstream> struct personen { struct personen *naechster; std::string name; int ordnungsnummer; std::string identifikation; } ; enum zustand {imON,imNamen,imID}; struct personen *ladedaten(ifstream &datei); struct personen *ladeperson(ifstream &datei); int main() { struct personen *wurzel=NULL; ifstream datei; datei.open("personen.txt"); wurzel=ladedaten(datei); while(wurzel!=NULL) { cout << wurzel->name << " besitzt die " << wurzel->ordnungsnummer << "mit der Identifikation " << wurzel->identifikation << "." << endl; wurzel=wurzel->naechster; } } struct personen *ladedaten( ifstream &datei) { struct personen *wurzel=NULL, *jetzt, *neu; while(!datei.eof()) { neu=ladeperson(datei); if (neu!=NULL) { if (wurzel==NULL) wurzel=neu; else jetzt->naechster=neu; jetzt=neu; } } return wurzel; } struct personen *ladeperson( ifstream &datei) { struct personen *fest; char puffer[100],zeichen; int zaehler; enum zustand zustand; fest=new struct personen; fest->naechster=NULL; zustand=imON; zaehler=0; for (;;) { datei.get(zeichen); if (datei.eof()) break; switch(zeichen) { case '"': puffer[zaehler]='\0'; zaehler=0; fest->ordnungsnummer=atoi(puffer); zustand=imNamen; break; case '(': if (zustand!=imON) { puffer[zaehler]='\0'; zaehler=0; fest->name = puffer; zustand=imID; } break; case ')': if (zustand!=imON) { puffer[zaehler]='\0'; zaehler=0; fest->identifikation=puffer; } puffer[zaehler]='\0'; zaehler=0; break; default: puffer[zaehler]=zeichen; zaehler++; break; } } }
-
"funktioniert nicht so ganz" ist keine brauchbare Fehlerbeschreibung.
-

Die Fehlermeldung lautet: "no return statement in function returning non-void"
Das Programm wird zwar durchlaufen, allerdings wird nichts ausgegeben.
-
... Hast du die Fehlermeldung mal VERSUCHT zu verstehen?
-
Ich sehe gerade, dass ich das Ende vergessen habe.
Müsste folgendes sein:struct beziehungen *sucheid(struct beziehungen *wurzel, char *bezeichnung) { while (wurzel != NULL) { if (!strcmp(wurzel->pate, bezeichnung)) return wurzel; wurzel = wurzel->naechster; } return NULL; }
-
Allerdings erhalte ich die Fehlermeldung:
invalid conversion from 'int' to 'const char*'
-
C.plusplus schrieb:
Allerdings erhalte ich die Fehlermeldung:
invalid conversion from 'int' to 'const char*'Wo erhältst du diese?
Damit das nicht so weiter geht, dass wir dir ständig alles aus der Nase ziehen müssen, lies mal dies durch:
https://www.c-plusplus.net/forum/200753
https://www.c-plusplus.net/forum/304133
http://www.tty1.net/smart-questions_de.html
-
if (!strcmp(wurzel->pate, bezeichnung)) return wurzel;Ich sehe in deinem code keinen pate.
Außerdem kenn ich nur einen Paten und der duldet keinen Widerspruch. Nicht einmal von einem Compiler.EDIT:
Du postest hier willkürlich ausgeschnittene/zusammengebastelte Codefragmente aber unglücklicherweise sind 99% der Forenmitglieder keine Hellseher.