if & std::cin



  • Hallo, ich versuche gerade eine Adressbuch zu schreiben. Und zwar habe ich eine frage und zwar habe ich mehre if Anweisungen die eine Eingabe bearbeiten. Jedoch sobald innerhalb des if ein std::cin (Z.13)vor kommt wird das else (Z.27)trotzdem ausgeführt. Wieso ist das so? Was muss ich anders machen?

    std::array < std::string, 10 > word_of_string(std::string s_in){
    	std::array< std::string, 10 > s_aaa;
    	unsigned int j=0,last_length=0;
    	for(unsigned int i=0;i<=s_in.length();++i){
    		if(s_in[i]==' '||s_in.length()==i){
    			for(unsigned int ii=last_length;i>ii;++ii){
    				s_aaa[j]+=s_in[ii];
    			}
    			last_length=i+1;
    			++j;
    		}
    	}
    	return s_aaa;
    }
    
    std::string s_in;
    std::cout<<">";
    std::getline (std::cin, s_in);
    
    while(s_in!="q"){
    	std::array< std::string,10> s_in_list=word_of_string(s_in);
    	if(s_in_list[0]=="load"){
    		int a;std::cin>>a;
    	}else if(s_in_list[0]=="create"){
    		if(s_in_list[1]=="entry"||s_in_list[1]=="address"){
    			std::string s_name,s_first_name,s_birthday,s_street,s_email;
    			unsigned int i_postal_code=0,i_house_number=0;
    			std::cout<<"name:";        std::cin>>s_name;
    			std::cout<<"first name:";  std::cin>>s_first_name;
    			std::cout<<"birthday:";    std::cin>>s_birthday;
    			std::cout<<"postal code:"; std::cin>>i_postal_code;
    			std::cout<<"street:";      std::cin>>s_street;
    			std::cout<<"house number:";std::cin>>i_house_number;
    			std::cout<<"email:";       std::cin>>s_email;
    			address_book.push_back(Entry(s_name,s_first_name,s_birthday,s_email,s_street,i_postal_code,i_house_number));
    		}else{
    			//error
    		}
    	}
    	...
    	else{
    		std::cout<<"error:Not accepted input\n";
    	}
    
    	std::cout<<">";
    	std::getline (std::cin, s_in);
    }
    

  • Mod

    Edit: Alles krasser Quatsch.



  • Das mit ja auch eigtliche so bewusst, jedoch so bald innerhalb des if zB: Z.13 ein cin vor kommt wirt "error:Not accepted input"(Z.27) ausgeben.wen ich das cin weg lasse dann nicht.


  • Mod

    Gib mal ein vollständiges Minimalbeispiel, erklär was du tust, was du erwartest, was stattdessen passiert. Möglichst auch in lesbar. Code wie s_aaa[j]+=s_in[ii]; wirkt eher wie IOCCC-Material. Kein Wunder, wenn du da selber den Überblick verlierst, was, wann, wo, warum passiert (diese vier Dinge musst du aber genau wissen über deine Programme).


  • Mod

    Um alle Wörter eines Strings in einem Array zu speichern, nimm lieber mal (anstatt deines Ansatzes mit word_of_strings )

    std::istringstream stream(s_in); // benötigt <sstream>
    std::vector<std::string> words( std::istream_iterator<std::string>{stream}, {} ); // benötigt <iterator>
    

    Eigentlich würde ich dich loben, dass du std::array verwendest, aber hier ist ein dynamisches Array wohl angebrachter.

    Wegen Zeile 20: Das kannst du verkürzen zu

    address_book.emplace_back( s_name, s_first_name, s_birthday, s_email, s_street, i_postal_code, i_house_number );
    

    Und was hungarische Notationen betrifft, sprich, den Typ jeder Variable mit einem Buchstaben im Namen andeuten: Schau hier.

    Man könnte stilistisch noch sicher deutlich mehr verbessern, aber was deinen Fehler anbelangt:

    1. Beachte dass, wenn du formattierte Extraktoren (also beispielsweise >> s die Zahlen einlesen) mit ungültigen Eingaben fütterst, das ganze in einer Endlosschleife endet.

    2. Beachte auch, dass, wenn du für eine der Eingaben in Zeile 13-19 mehr als ein Wort eingibst, diese überschüssigen Wörter vom nächsten >> aufgefressen werden (und es ggf. böse enden kann, siehe 1.).

    3. Aber vor allem beachte dass cin >> s_email (Z. 19) nicht das Newline hinter dem Wort löscht! Das musst du selbst machen, damit getline dahinter sich nicht verfängt:

    // ...
    std::cout<<"email:";       std::cin>>s_email;
    std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
    

    Liest du einen std::string mit >> ein, werden zuerst alle Whitespaces übersprungen - dann wird ein Wort eingelesen:
    Sobald nach dem ersten nicht-Whitespace Zeichen wieder ein Whitespace gefunden wird, wie ein Newline, wird die Extraktion als Erfolgreich beendet, aber das Whitespace bleibt im Stream stecken. getline wird dann einen leeren String in s_in speichern.



  • Erst mal vielen dank,

    ich hätte jedoch noch ein paar fragen und zwar:
    1. Ist es besser eine Variable str_name anstatt s_name zu nennen?
    2. Wie sollte ich am besten das Problem mit der Endlosschleife lösen? Einen string einlessen, prüfen ob zahl, ...?
    3.Da wo "std::streamsize::max()" reicht doch in dem Fall eine 1 schirbe oder ?

    Arcoth schrieb:

    std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
    

    sorry mus noch viele lernen^^


  • Mod

    1. Ist es besser eine Variable str_name anstatt s_name zu nennen?

    Nein, du sollst es einfach name nennen.

    2. Wie sollte ich am besten das Problem mit der Endlosschleife lösen? Einen string einlessen, prüfen ob zahl, ...?

    Nein, prüfen ob die Eingabe erfolgreich war. Wie du das hinbekommst: Schau in dein Grundlagenbuch!

    3.Da wo "std::streamsize::max()" reicht doch in dem Fall eine 1 schirbe oder ?

    Du hast wohl vergessen <limits> einzubinden?



  • Du hast wohl vergessen <limits> einzubinden?

    Ups ja thx


  • Mod

    Oh, Mist. Ich habe gerade einen Riesenbeitrag verfasst, mit Beispielen und alles im Details erklärt und kurz bevor ich fertig war, muss ich irgendeine komische Tastenkombination gedrückt haben und nun ist alles weg. Ich weiß, diese Meldung trägt nichts zum Thread bei, aber das ist so ärgerlich, das muss ich gerade einfach ablassen. 😡 😡 😡

    P.S.: Die wichtigsten Punkte:
    -Deine Datentypen passen nicht. Postleitzahlen und Hausnummern sind keine Zahlen. Im Prinzip ist alles String.
    -operator>> ist hier ebenfalls nicht angemessen, da fast alle (alle?) der Datenfelder auch Leerzeichen enthalten können (operator>> trennt bei allen Whitespaces).
    -Die übliche Vorgehensweise wäre, das Einlesen in eine Funktion zu packen, die einen Fehlerstatus zurück gibt. Die ruft man auf, dann prüft man den Fehlerstatus, dann (und nur bei Erfolg) speichert man das Ergebnis. Da die Daten hier alle Zeichenketten sind, wäre so eine Funktion einfach eine Verkettung vieler getlines. Und da getline selber ggf. einen Fehlerstatus im Stream setzt, muss man das nicht einmal selber machen.
    -Das wurde hier im Forum schon sehr oft diskutiert. Oft ist in Threads über Eingabeprobleme der Nutzer "Werner Salomon" aktiv. Darüber kannst du gezielt mittels der Forensuche (oder besser: Google mit "site:www.c-plusplus.net") nach diesen Threads suchen.


Anmelden zum Antworten