Mischung von operator>> und getline. War: kahlme00s Kaperung von "In Rekursion Wert mitnemen"



  • Hallo Leute

    Bin Neu in der C++ welt und lerne gerade, wie man mit Strukturen arbeiten kann.
    Meine Aufgabe ist ein adressenvewaltungsprogramm zu schreiben und mein C++ code sieht folgendermaßen aus:

    #include<iostream>
    #include"Header.h"
    using namespace std;
    Adress *padr;
    int main()
    {
    	int i,anzahl,auswahl;
    	do{
    	cout<<"ADRESSNVERWALTUNG:\n\n";
    	cout<<"<1> Neue Adresse eingeben\n";
    	cout<<"<2> Adressen ausgeben\n";
    	cout<<"<3> Eine Adresse aendern\n";
    	cout<<"<4> Adressen sortieren\n\n";
    	cout<<"<5> Programm beenden\n\n";
    	cout<<"Ihre Auswahl bitte: ";
    	cin>> auswahl;
    	cout<<endl;
    	switch(auswahl)
    	{
    	case 1: cout<<"Wieviel Adressen moechten eingeben: ";
    			cin>>anzahl;
    			padr = new Adress[anzahl];
    			eingabe(anzahl);
    			break;
    die Funktion eingabe sieht so aus:
    
    void eingabe(int anzahl)
    {
    	int i;
    	for(i=0;i<anzahl;i++)
    			{
    				cout<<endl;
    				cout<<"Angaben zur "<< i+1 <<" Person eingeben:\n\n";
    				cout<<"Name: ";
    				cin.getline(padr[i].Name, 41);
    				cout<<"Vorname: ";
    				cin.getline(padr[i].Vorname, 41);
    				cout<<"Strasse: ";
    				cin.getline(padr[i].Strasse, 41);
    				cout<<"PLZ: ";
    				cin.getline(padr[i].PLZ, 41);
    				cout<<"Ort: ";
    				cin.getline(padr[i].Ort, 41);
    				cout<<"Telefon: ";
    				cin.getline(padr[i].Tel, 41);
    				cout<<endl<<endl;
    			}
    }
    

    Das Program ist vom compiler her fehlerfrei. Nun beim eingabe der ersten adresse
    erscheint immer Name: Vorname:
    also immer die eingabe für Name wird übersprungen und ich weiss nicht warum. ab der zweiten adresse ist alles in Ordung.

    wäre für jede erklärung sehr dankbar

    gruß kahlme00

    ^edit durch SeppJ: cpp-Tags eingefügt^


  • Mod

    Bitte einen passenden Thread mit passender Überschrift aufmachen, keine alten Threads, noch dazu mit völlig unpassendem Thema, kapern. cpp-Tags benutzen (links unter den Smileys), um Code zu formatieren. Ich mache das ausnahmsweise mal für dich, beim nächsten mal bitte selber richtig machen.


  • Mod

    Benutze keine globalen Variablen, benutze niemals new[], std::vector ist immer die viel bessere Alternative. Benutze nicht ohne Not char-Arrays, std::string ist fast immer die bessere Alternative (hier sogar ganz eindeutig). Benutze nicht endl, wenn du '\n' meinst. endl ist nämlich '\n' und flush(), das möchtest du meistens nicht, außer vielleicht unmittelbar vor einer Eingabe oder am Ende einer längeren Ausgabe. Definiere Variablen so lokal wie möglich (siehe auch globale variablen oben), anstatt am Funktionsanfang. Insbesondere bei Zählvariablen in einer for-Schleife hast du ausdrücklich die Chance for(int i = ... zu benutzen.

    Dies alles sind mittelschwere bis schwere Designmängel die man auch als Anfänger nicht machen sollte und sich keinesfalls angewöhnen sollte. Meine Vermutung: Ganz schlechter Lehrer. Falls du das aus einem Buch oder Tutorial hast: Welches? Siehe meine Signatur für gute Buchtipps.

    Dein Design könnte insgesamt verbessert werden, wenn deine Adressklasse besser gestaltet wäre, insbesondere mit einem eigenen Leseoperator, aber das ist vermutlich noch zu schwer für dich, deswegen habe ich es oben nicht aufgeführt, denn das lernst du ja anscheinend gerade.

    Dein Fehler geht schon aus der Überschrift hervor, den ich für deinen Thread gewählt habe:
    Denk dir die Streams von C++ (cin und cout sind z.B. Instanzen eines istream bzw. eines ostream) als eine lange Reihe von Zeichen. An dieser Reihe kann man entlangfahren mit den Eingabe- bzw. Ausgabeoperationen. Denk dir cin >> zahl; nicht als "Befehl, der eine Zahl von der Tastatur liest", sondern als eine Aktion die auf der langen Reihe von Zeichen operiert die irgendwie in dein Programm eingegeben wird.
    Wenn du mit dem Operator>> etwas einliest, dann wird normalerweise führender Whitespace übersprungen und danach bis zum nächsten Whitespace gelesen, oftmals ist dies der Zeilenumbruch '\n' mit dem ein Anwender seine Eingaben abschließt. Der Zeilenumbruch wird dabei nicht mitgelesen!. getline hingegen liest bis inklusive dem nächsten Zeilenumbruch. Wenn ein getline direkt auf eine Leseaktion mit operator>> folgt, dann wird daher einfach nur der Zeilenumbruch gelesen, der noch im Eingabestrom verblieben ist und die Rückgabe von getline ist eine Leerzeile.

    Abhilfe ist, entweder mit der Mischung von formatierten Leseaktionen(z.B. operator >>) und unformatierten Leseaktionen (z.B getline) zurückhaltender zu sein. Wenn du sie doch mischt, dann solltest du vorher prüfen, ob vor dem getline vielleicht noch Whitespace im Eingabestrom sitzt, den du nicht möchtest und dies gegebenenfalls mit ignore überspringen. Guck dir mal die ganzen verschiedenen Aktionen an, die man auf Eingabeströmen machen kann:
    http://www.cplusplus.com/reference/iostream/istream/
    Da fällt dir bestimmt was passendes ein.



  • Hallo SeppJ

    Danke für die Aufmachung eines neuen Threads und die Formatierung. wusste nicht, wie man das macht. jetzt weiss ich. Danke auch für die kosbaren Tipps.

    Ueber die Mischung von Operrator >> und getline habe ich in der Seite, die du mir empholen hast nachgeschaut und habe mich entschieden fuer cin.ignore() entschieden.
    Meine Frage ist:
    sollte ich, wenn ich cin.getline() anwende, immer auf cin>> verzichten. Z.B wenn ich einen Integer Wert einlesen will, also als char deklarieren und als char einlesen und danach mit der Funktion atoi() umwandeln?.

    Übrigens ich kann momentan nur mit new[] arbeiten, wenn ich Speicher dynamisch reservieren will. habe keine Ahnung von std::vector und std::strings oder wurde in meinem Buch bis jetzt nicht erwähnt. alles andere habe ich geändert, so wie du gesagt hast.

    Mein Buch heisst C++ für IT-Berufe von Dirk Hardy: C++ für IT-Berufe | ISBN: 9783808585498.
    Danke im Voraus.


  • Mod

    kahlme00 schrieb:

    sollte ich, wenn ich cin.getline() anwende, immer auf cin>> verzichten. Z.B wenn ich einen Integer Wert einlesen will, also als char deklarieren und als char einlesen und danach mit der Funktion atoi() umwandeln?.

    Nein, nicht verzichten. Das Problem löst sich mehr oder weniger alleine, wenn du später für deine Klassen brauchbare Ein- und Ausgabeoperatoren selber schreibst. Ich fürchte jedoch, das wird in deinem Lehrbuch nie kommen, da es schlecht ist. Deine Kenntnis von atoi aber Unkenntnis von Stringstreams deutet darauf hin.

    Übrigens ich kann momentan nur mit new[] arbeiten, wenn ich Speicher dynamisch reservieren will. habe keine Ahnung von std::vector und std::strings oder wurde in meinem Buch bis jetzt nicht erwähnt.

    Ein ganz schlimmes Alarmsignal. Wegwerfen. Oder der Jahreszeit gemäß als Grillanzünder benutzen.



  • Werde ich machen aber erst im Juli 🙂

    Nun habe ich folgendes Problem, ich moechte die Adressen Nach Namen aussortieren, dazu soll ich den bubblesort algorithmus anwenden. Habe das gemacht aber gefällt mir nicht die Art, wie ich das gelöst habe, da ich eine Hilfsfunktion namens

    void tausche(Adress *A, Adress *B)
    

    anwenden soll. Leider weiss ich nicht wie.
    Meine Lösung sieht so aus:

    void bubblesort(Adress *S, int anzahl)
    {
    	Adress help;
    	for(int i=anzahl-2;i>=0;i--)
    		for(int j=0;j<=i;j++)
    		{
    			if(S[j].Name[0] > S[j+1].Name[0])
    			//if(strcmp(S[j].Name, S[j+1].Name)>0)
    			{
    				//struct Adress help = S[j];
    				help = S[j];
    				S[j] = S[j+1];
    				S[j+1] = help;
    			}
    		}
    }
    

    Wäre für jeden Hinweis sehr dankbar.
    Übrings das Speicherreservierung mit <vector> klappt wunderbar. Leider kämpfe ich immer noch mit <strings>.


  • Mod

    Deine Zeilen 11-13 sind höchstwahrscheinlich das ,was auch in der tausche-Funktion steht. Einfach ersetzen.

    Und dein Lehrbuch zeigt einmal mehr seine Schwächen. Hier Pointer zu benutzen macht überhaupt keinen Sinn, Referenzen wären angesagt. Und natürlich der ganze andere Mist, wie dass hier mit rohen Arrays hantiert wird und dass man die Standardbibliothek schlecht nachprogrammiert.


Anmelden zum Antworten