C++ Unbekannte Anzahl von strings einlesen

badday

Commander
Registriert
Sep. 2007
Beiträge
3.023
Moin zusammen,

ich schreibe gerade an einem kleinen Programm, dass eine unbekannte Anzahl von Strings einliest, diese in einen Vektor schreibt und nach Abschluss von allem den Inhalt des Vektors ausgibt.

Code:
#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{

        vector<string> svec;
        string word="";
        while(cin>>word)
        {
            svec.push_back(word);


        }



        for(vector<string>::iterator iter=svec.begin(); iter!=svec.end(); iter++)
        {
                cout<<*iter<<endl;

        }

    return 0;

}


Wie man sieht keine große Geschichte. Das Problem liegt nun offenbar darin, dass cin>>word niemals den Wert false anzunehmen scheint und ich daher aus der Schleife nicht herauskomme.
Ich habe im Internet diverse Seiten gefunden, aber keine gute Lösung gesehen.
Was mich auch überrascht ist, dass auf einigen Seiten genau dieses Einlesen in den String beschrieben wird, ebenfalls in einer Schleife und es dort offenbar funktioniert.

Was allerdings funktioniert, ist, wenn ich in der Schleife word ausgeben würde, also cout<<word<<endl; einfügen würde. Dann wird die schleife beendet.
Soweit ich weiß wird hier der Eingabepuffer geleert. Meine Frage nun: Wie mache ich das manuell? Also ohne die Hilfe von cout?
Habe auch danach gesucht, aber keine Lösung gefunden.

Vielen Dank und ein gutes neues Jahr,

badday
 
Du könntest die While-Schleife doch auch einfach so lange laufen lassen, wie cin>>word ungleich einer Leereingabe bzw, eines fest ausgemachten Ende-Zeichens ist.
 
Wenn Du von stdin liest musst du ein EOF (End Of File) schicken, damit die Schleife beendet wird (analog zum Lesen von Dateien); dies machst Du in der Konsole per Strg+D.
 
Das EOF-Bit sollte doch automatisch auf false gesetzt werden, sobald die Eingabe leer ist (sprich das Ende der Eingabe erreicht ist), oder?

Gruß,

badday
 
while(cin>>word) bricht bei EOF ab und auch, wenn das nächste einzulesende Zeichen ein Whitespace ist. (isspace(c, is.getloc()) -> true)

Wenn im Extractor kein Zeichen aus dem Stream gelesen wurde, so wird das Failbit gesetzt und while(cin >> word) sollte sich zu false auswerten.

Du arbeitest mit der Konsole, richtig? Keine gepipeten Dateien? Hast du einfach mal 2 mal Enter gedrückt zum Beenden?
 
Schwierig zu sagen. Ich seh erstmal keinen offensichtlichen Fehler (was nix heißen muss). Falls du die Bash benutzt, mach mal (bzw. das Pendant für deine Shell)
LC_ALL=C
export LC_ALL

und schau mal, ob es sich damit löst. Dann ist es möglicherweise irgendeine Locale-Geschichte, die zuschlägt. Aber - das ist auch nur geraten.

Ah, ansonsten - welche GCC/G++-Version?
 
Ich benutze gcc (GCC) 4.4.2 20091027 (Red Hat 4.4.2-7).
Dein Vorschlag hat leider nichts gebracht.
Um zu überprüfen, ob das eof-Bit gesetzt ist, habe ich folgendes versucht:
while(cin>>word)
{
svec.push_back(word);
if(!cin.eof())
cout<<"Es ist nicht gesetzt"<<endl;

}
Und siehe da: Es ist nicht gesetzt. Sollte es das nicht eigentlich sein?

Gruß,

badday
 
Nein, darf es nicht.

Der extractor (operator>> für std::string) kann das Failbit setzen, wenn nichts extrahiert wurde. EOF kommt an der Tastatur nur über spezielle Shellcodes (Ctrl+D z.B., aber das hängt von der Shell bzw. ggf. Terminal-Emulation ab).

Und das ist auch das, was dir ein while(cin) überprüft. Da wird, geprüft, ob der Stream "good" ist. Das ist er, wenn weder das fail-bit noch das bad-bit gesetzt ist. Daher ist die Prüfung eigentlich absolut sauber.

Edit: *grübel* Hast du als Zeichenkodierung vielleicht Unicode in der Shell aktiviert?
Edit2: Mein Fehler, EOF wird da nicht geprüft, tut aber auch nichts zur Sache soweit, da die While-Schleife nach dem ersten EOF auf Fail geht.
 
Zuletzt bearbeitet:
Das dies alles geprüft wird ist mir schon klar, aber sollte da nicht ein Bit gesetzt werden? Wohl ja, sonst würde das ja nie gehen. Aber welches?
Wenn ich versuche
if(word=="")
cin.setstate(istream::failbit);
So funktioniert dies auch nicht, da er offenbar nur in word schreibt, wenn es etwas zu schreiben gibt. Wie aber kann ich dann diesen Zeitpunkt ermitteln?

Gruß,

badday
 
Zuletzt bearbeitet:
Es sollte wenn, dann das Failbit gesetzt werden.

*grübel*

Anderer Ansatz: Was steht denn im String, nachdem du zweimal Enter gedrückt hast?
Hau doch mal ein copy( word.begin(), word.end(), ostream_iterator<int>(cout, "\n")) rein (evtl. iterator und algorithm includen), dann siehst du, welche numerischen Zeichencodes im String stehen bleiben.
 
Offenbar hat der String noch den vorherigen Inhalt...
Wenn ich deinen Vorschlag verwirkliche erhalte ich z. B.
computerbase
99
111
109
112
117
116
101
114
98
97
115
101
here
104
101
114
101
Die letzten beiden Enter scheinen offenbar "nichts" gemacht zu haben.

Gruß,

badday
 
Ein Königreich für einen Compiler... *grumpf* Hab gerade keinen zur Hand, sonst würde ich mir das gleich mal genauer anschauen. Hmmm doof. :-/ Bin gerade auch etwas planlos (oder ich seh's nur einfach nicht).

Hast du mal ausprobiert, wie sich dein Programm mit einer gepipeten Datei verhält? Gib mal ruhig die Fehlerbits nach jedem Lesen aus.
 
Obgleich mir die Bedeutung des Wortes "gepipeten" nicht bekannt ist (oder ist das ein Schreibfehler?), habe ich folgendes gemacht:
#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <fstream>



using namespace std;

int main()
{

vector<string> svec;
string word="";
ifstream file("/home/USERNAME/Desktop/datei.conf");
while(file>>word)
{
svec.push_back(word);


}



for(vector<string>::iterator iter=svec.begin(); iter!=svec.end(); iter++)
{
cout<<*iter<<endl;

}

return 0;

}
Und siehe da: Er liest alles schön ein und gibt alles aus, wie gewollt. Wie bekomme ich das nur bei der Standardeingabe hin?

Gruß,

badday
 
Ah "gepipet"... Kunstwort. :-) Einfach alles über Pipe 0 (stdin) an das Programm schicken. Also entweder cat test.txt | programm oder programm < test.txt.

So und ich merke auch gerade, dass ich schön doof bin. *g* Das kann natürlich so nicht funktionieren.
In einem operator>> für formatierten Input (also auch bei std::string) steht am Anfang immer das Sentry-Objekt. Dieses futtert alle Whitespaces bis zum ersten nicht-Whitespace-Zeichen, sofern nicht das noskipws Flag gesetzt ist. Kommen nun ein paar Enter hintereinander an, Leerzeichen oder irgendwas, werden diese schlicht und ergreifend ignoriert und das Programm steht weiter im operator>>. Damit kann dort auch niemals ein Leerstring bei rauskommen, es sei denn der Stream ist tatsächlich "bad" oder EOF etc.
Da man hier mit formatiertem Input nicht weiterkommt, muss man auf unformatierten Output zurückgreifen - z.B. getline.

Folgendes Programm hört nach einer Zeile ohne enthaltene Wörter auf:
Code:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <string>
#include <sstream>

using namespace std;

int main()
{
  vector<string> words;
  string line;
  while( getline( cin, line)) {
    istringstream iss( line);
    string word;
    unsigned i = 0;
    while( iss >> word) {
      words.push_back( word);
      ++i;
    }
    if( i == 0) {
      break;
    }
  }

  cout << "output:" << endl;

  copy( words.begin(), words.end(), ostream_iterator<string>( cout, "\n"));
}
 
Zurück
Oben