Klassen / Zeigerfeld - Fehlerhafte Ausgabe
-
Hi,
ich bin gerade dabei eine stark vereinfachte Personendatenbank zu basteln. Das ganze soll sich komplett im Eingabefenster, also mit sehr einfachen Mitteln abspielen und dient ausschließlich der Übung. (Insbesondere Stichwort: Klassen) Meine C++ Kenntnisse entsprechen etwa einem Semester Informatik als Nebenfach mit einer Wochenstunde, sind also recht überschaubar
Der Compiler (Dev-C++) meldet zwar keinen Fehler im Quellcode, dennoch erhalte ich an einer Stelle nicht das gewünschte Ergebnis.
Ich definiere eine Klasse Person mit
private: string Name; [...] public: void setName(string N){Name=N;}; string getName(){return Name;};sowie zwei public abgeleitete Klassen Student und Mitarbeiter
Im Hauptprogramm bastele ich mir eine Art Menü, das mir mit Hilfe einer while-Schleife immer wieder die Auswahlmöglichkeiten anzeigt, eine davon ausführt, wieder anzeigt....
Da das ganze nicht allzu lang ist und ich nicht weiß was ich davon kürzen soll ohne die mögliche Fehlerquelle wegzunehmen, erlaube ich mir mal den Code komplett zu posten.Mein Problem:
Wähle ich Punkt 3, also die Anzeige aus, erhalte ich kryptische Zeichen und ein Piepsen...bool end=false; int anz=0, auswahl, anzmit=0, anzstu=0; string tempname; Mitarbeiter *mitarb = new Mitarbeiter[anz]; Student *student = new Student[anz]; int main(){ //Hauptmenü while(end==false) { cout<<"****Personendatenbank****"<<endl [..] cin>>auswahl; switch(auswahl) { case 1: { cout<<"Wie viele Mitarbeiter moechten Sie anlegen?"<<endl; cin>>anz; anzmit=anz; Mitarbeiter *mitarb = new Mitarbeiter[anz]; for(int i=0; i<anz; i++){ cout<<"\nBitte Name von Mitarbeiter "<<i+1<<" eingeben"<<endl; cin>>tempname; mitarb[i].setName(tempname); } break; } case 2: { cout<<"Wie viele Studenten moechten Sie anlegen?"<<endl; cin>>anz; anzstu=anz; Student *student = new Student[anz]; for(int i=0; i<anz; i++){ cout<<"\nBitte Name von Student "<<i+1<<" eingeben"<<endl; cin>>tempname; student[i].setName(tempname); } break; } case 3: { cout<<"Mitarbeiter:"<<endl; for(int i=0; i<anzmit; i++){ cout<<mitarb[i].getName()<<endl; } cout<<"Studenten:"<<endl; for(int i=0; i<anzstu; i++){ cout<<student[i].getName()<<endl;} break; } } //switch ende } //while Ende getch(); }Das Ganze ist bestimmt nicht allzu elegant und alles andere als vollständig, ich wäre allerdings schon äußerst zufrieden, wenns einfach nur das machen würde, was ich von ihm möchte.
Ich wäre sehr dankbar, wenn mir jemand die Fehlerquelle mitteilen würde.
lg
-
Bäh! Das Ganze ist von Specherlecks durchzogen, nutze bitte
std::vector. Kommst du zufällig von C
?
-
In den case 1- und case 2 Blöcken hast du jeweils einen eigenen Zeiger definiert und dorthin geschrieben, im case 3 Block nutzt du die globalen Arrays.
Abgesehen davon strotzt dein Code nur so vor Speicherlecks - und du solltest eher mit std::vector<> arbeiten als mit nackten Zeigern.
-
CStoll schrieb:
In den case 1- und case 2 Blöcken hast du jeweils einen eigenen Zeiger definiert und dorthin geschrieben, im case 3 Block nutzt du die globalen Arrays.
Abgesehen davon strotzt dein Code nur so vor Speicherlecks - und du solltest eher mit std::vector<> arbeiten als mit nackten Zeigern.
Einer der Mitgründe für die Probleme ist die großzügige Verwendung globaler Variablen. Daran solltest du, neben den anderen genannten Sachen, ebenfalls arbeiten.
-
Ich glaub euch gern, dass das ganz recht grausig aussieht, wenn man ne Ahnung davon hat

Tatsächlich scheint mein Prof irgendwie an C zu hängen. Der Großteil seiner Folien scheint komplett auf C++ Elemente zu verzichten.
Diese bringt er nur in der Theorie immer mal wieder ein, bemerkt dass das ganze ja sehr praktisch ist, aber weißt eigentlich kaum auf die grundsätzlichen Unterschiede hin.Ich habe auch noch nie was von vectors gehört... Mein ganzes Skript nutzt Zeiger im Prinzip auf die Weise wie ich oben (vielleicht aber wenigstens noch so dass es dann läuft
)Kann man das Programm auf diese Weise noch irgendwie retten?
(Wie erreiche ich also, dass ich in den cases 1 und 2 Objekte aus den entsprechenden Klassen erhalte und fülle und dann in 3 auf ebendiese zugreifen kann?)Oder sollte ich mir wirklich mal die Vektor-Variante anschauen und ist das aus einigermaßen gut zu verstehen und umzusetzen?
Gedacht ist diese Aufgabe wohl ohne - da ich einfach noch nie was davon gehört habe - aber wenns dringend anzuraten ist, versuch ich mich da auch gerne.
-
wildschwein schrieb:
Oder sollte ich mir wirklich mal die Vektor-Variante anschauen und ist das aus einigermaßen gut zu verstehen und umzusetzen?
Gedacht ist diese Aufgabe wohl ohne - da ich einfach noch nie was davon gehört habe - aber wenns dringend anzuraten ist, versuch ich mich da auch gerne.Prinzipiell gilt dass ein
std::vectorimmer einem rohen Array vorzuziehen ist. Und du hast mein volles Beileid: Viel zu oft bekommen Leute an Unis (o.ä.) "C mit cout" erklärt. Und da es "C mit cout" ist arbeitet man mit gefährlichen Arrays.
-
Frag doch mal deinen Professor, wo er C++ gelernt hat

wildschwein schrieb:
Kann man das Programm auf diese Weise noch irgendwie retten?
(Wie erreiche ich also, dass ich in den cases 1 und 2 Objekte aus den entsprechenden Klassen erhalte und fülle und dann in 3 auf ebendiese zugreifen kann?)Erste Notfallmaßnahme wäre es, nur einen Satz an Zeiger-Variablen zu verwenden (und die am besten so lokal wie möglich, d.h. für dich in der main()-Funktion). Allerdings benötigst du noch einiges mehr an Speicherverwaltung, um daraus etwas fehlerfreies machen zu können
Oder sollte ich mir wirklich mal die Vektor-Variante anschauen und ist das aus einigermaßen gut zu verstehen und umzusetzen?
Ja, das solltest du.
Gedacht ist diese Aufgabe wohl ohne - da ich einfach noch nie was davon gehört habe - aber wenns dringend anzuraten ist, versuch ich mich da auch gerne.
Es ist trotzdem besser, du gewöhnst dir frühzeitig einen vernünftigen Stil an, das erleichtert dir das Leben auch, wenn du mit dem Studium fertig bist und dieses Wissen in der Praxis anwenden darfst.
-
wildschwein schrieb:
Kann man das Programm auf diese Weise noch irgendwie retten?
Retten nur in dem Sinne, dass man daraus etwas machen könnte, das bei vorsichtiger Behandlung eventuell nicht explodiert. Aber die Speicherlöcher sitzen zu tief, als dass man sie wirklich zuverlässig loswerden könnte. Da muss eine grundlegend andere Vorgehensweise her als Pointerfrickelei.
(Wie erreiche ich also, dass ich in den cases 1 und 2 Objekte aus den entsprechenden Klassen erhalte und fülle und dann in 3 auf ebendiese zugreifen kann?)
Es sollte reichen, wenn du in den case-Fällen deinen globalen Variablen das neue Feld zuweist anstatt neue Pointer anzulegen. Also
student = new Student[anz]stattStudent *student = new Student[anz]und beim Mitarbeiter ebenso. Das Programm hat dann aber immer noch andere Probleme.Oder sollte ich mir wirklich mal die Vektor-Variante anschauen und ist das aus einigermaßen gut zu verstehen und umzusetzen?
So sähe eine robuste Lösung mit vector aus. Da kann eigentlich nichts schiefgehen, außer dass die Eingaben nicht auf Erfolg geprüft werden (d.h. wenn jemand einen Buchstaben eingibt, wo eine Zahl erwartet wird, passieren komische Dinge):
#include<string> class Person { private: std::string Name; public: // void setName(string N){Name=N;}; // Da der Name sich wohl nicht ändern wird, schreiben wir das im // Konstruktor und lassen den Setter mal lieber sein: Person(const std::string& name): Name(name) {} std::string getName(){return Name;} // Nach Funktionen braucht kein Semikolon }; class Mitarbeiter: public Person { public: Mitarbeiter(const std::string& name): Person(name) {} }; class Student: public Person { public: Student(const std::string& name): Person(name) {} }; // Globale Variablen lassen wir mal lieber ganz weg. Gibt nur Scherereien #include<iostream> #include<vector> using namespace std; int main(){ bool end = false; vector<Student> studenten; vector<Mitarbeiter> mitarbeiter; //Hauptmenü while(end==false) { cout<<"****Personendatenbank****"<<endl; int auswahl; cin>>auswahl; switch(auswahl) { case 1: { cout<<"Wie viele Mitarbeiter moechten Sie anlegen?"<<endl; int anz; cin>>anz; for(int i=0; i<anz; i++){ cout<<"\nBitte Name von Mitarbeiter "<<i+1<<" eingeben"<<endl; string tempname; cin>>tempname; mitarbeiter.push_back(tempname); // hier wird der Konstruktor implizit aufgerufen } break; } case 2: { cout<<"Wie viele Studenten moechten Sie anlegen?"<<endl; int anz; cin>>anz; for(int i=0; i<anz; i++){ cout<<"\nBitte Name von Student "<<i+1<<" eingeben"<<endl; string tempname; cin>>tempname; studenten.push_back(tempname); } break; } case 3: { cout<<"Mitarbeiter:"<<endl; for(int i=0; i<mitarbeiter.size(); i++){ cout<<mitarbeiter[i].getName()<<endl; } cout<<"Studenten:"<<endl; for(int i=0; i<studenten.size(); i++){ cout<<studenten[i].getName()<<endl;} break; } } //switch ende } //while Ende }
-
Wow, danke für eure Antworten!
Auch wenn ich die Funktionsweise von Vektoren noch nicht völlig verstehe, wirkt die Variante trotzdem deutlich angenehmer.
Ich werde mich morgen mal ausführlicher damit beschäftigen und vielleicht auch nochmal mit meinem Übungsleiter drüber reden.Vielen Dank soweit

-
wildschwein schrieb:
Wow, danke für eure Antworten!
Auch wenn ich die Funktionsweise von Vektoren noch nicht völlig verstehe, wirkt die Variante trotzdem deutlich angenehmer.
Ich werde mich morgen mal ausführlicher damit beschäftigen und vielleicht auch nochmal mit meinem Übungsleiter drüber reden.Vielen Dank soweit

Den Kerl einfach hier vorbeischicken, den Rest kriegen wir schon hin

-
So, nachdem ich mich jetzt nach einiger Zeit mit anderen Prioritäten mal wieder intensiv mit meiner kleinen Aufgabe hier auseinandersetzen konnte, möchte mich mich nochmal bedanken.
Das Programm ist mittlerweile deutlich gewachsen und seitdem ich alles mit Vektoren schreibe, hatte ich keine größeren Pausen wegen unauffindbarer Fehler mehr und es läuft insgesamt ganz wunderbar.
Mein Übungsleiter schein zwar zwischenzeitlich etwas verwirrt, als er keine guten alten Arrays gefunden hat und musste erstmal fragen, was ich denn da gemacht habe, ist aber doch sicher zufrieden, dass die Sache so schön läuft
An dieser Stelle habe ich nochmal eine Frage:
Ich würde die Vektoren nun gerne auslesen, abspeichern und bei Programmstart wieder einlesen.
Darüber habe ich bisher leider noch nie was gehört.
Ich könnte mir vorstellen, dass das mit fprintf und irgendeiner Funktion, die die Textdatei dann wieder wie gewünscht verarbeitet, klappt.
Ich würde mich freuen, wenn mir jemand kurz eine möglichst anfängerfreundliche Methode zeigen könnte - evtl genügt auch ein Stichwort oder ein Link.Die Frage hat ja nicht mehr allzu viel mit meinem ursprünglichen anliegen zu tun, wenns gewünscht wird kann ich auch gern nen neuen Thread erstellen.
-
wildschwein schrieb:
mit fprintf
Ist auch aus C. Nutze
std::fstream:#include <fstream> int main() { std::ifstream Read("Filename.txt"); //Von Read lesen Read.close(); //Bin mir nicht sicher ob nötig oder nicht std::ofstream Write("Filename.txt"); //Nach Write schreiben }
-
EOutOfResources schrieb:
#include <fstream> int main() { std::ifstream Read("Filename.txt"); //Von Read lesen Read.close(); //Bin mir nicht sicher ob nötig oder nicht std::ofstream Write("Filename.txt"); //Nach Write schreiben }Dafür hat uns der Herr Blöcke geschenkt.
#include <fstream> int main() { { std::ifstream Read("Filename.txt"); //Von Read lesen }//Schwuppduwupp, und Read ist weg. std::ofstream Write("Filename.txt"); //Nach Write schreiben }
-
volkard schrieb:
Dafür hat uns der Herr Blöcke geschenkt.
Ich finde unbedingte Scopes hässlich.
-
EOutOfResources schrieb:
volkard schrieb:
Dafür hat uns der Herr Blöcke geschenkt.
Ich finde unbedingte Scopes hässlich.
Dafür kann ich nicht aus Versehen von Read lesen, nachdem er geschlossen wurde.
-
volkard schrieb:
Dafür kann ich nicht aus Versehen von Read lesen, nachdem er geschlossen wurde.
Stimmt, daran habe ich nicht gedacht.
-
#include <fstream> int main() { std::ifstream Read("Filename.txt"); //Von Read lesen Read.close(); //Bin mir nicht sicher ob nötig oder nicht #define Read (void)("dead name") std::ofstream Write("Filename.txt"); //Nach Write schreiben }
-
Warum nicht read/write in freie Funktionen auslagern?
-
Danke für eure Antworten!
Wenn ich nun mit ofstream eine Textdatei so beschreibe, dass in jeder Zeile genau ein Attribut(Strings bzw Integers) eines Elements meines Vektors steht, wobei für unterschiedliche Attribute unterschiedliche Dateien verwendet werden - wie kann ich diese wieder zeilenweise auslesen? Klappt das auch wenn ich Zahlen (in dieser Datei steht dann also nix anderes) direkt wieder als integer betrachten möchte?
Bin bisher v.a. auf getline() gestoßen, aber ich werd um die Uhrzeit irgendwie nicht mehr recht schlau draus

-
Ich würde die Daten auf jeden Fall nicht auf mehrere Dateien verteilen, sondern jedes Objekt "am Stück" (d.h. die einzelnen Attribute hintereinander) speichern. Dazu schreibst du dir z.B. zwei Methoden, die jeweils ein Element lesen bzw. schreiben können und kannst diese dann auf den gesamten vector<> anwenden (die hohe Kunst ist es, dafür die Stream-Operatoren zu überladen).