C++: Die Basics - eps1.5_EingabeAusgabe
Wo komme ich her? Wo gehe ich hin? Ergib das alles einen Sinn? Mit diesen Fragen beschäftigen sich Philosophen und Geistige seit Menschheitsgedenken. Doch bisher fand noch niemand eine endgültige Antwort darauf.
Nein, ich befinde mich nicht in einer Sinnkrise und habe auch nicht vor, sieben Jahre asketisch in Tibet zu leben. Mir erscheint es eher eine so grundlegende Fragestellung zu sein, dass sie in abgewandelter Form genauso gut auf unser Thema passt.
Wo kommen die Daten her?
Wo gehen die verarbeiteten Daten hin?
Ergibt meine Programmierung überhaupt einen Sinn?
System, System in der Hand, sag mir…
Kannst du dich noch an unser erstes Programm erinnern? Da haben wir den Computer „Hello World!“ auf der Konsole anzeigen lassen. Die Ausgabe auf dem Bildschirm dient dir zur Kontrolle, ob das Programm überhaupt funktioniert. Ohne diese optische Rückmeldung kannst du kaum die Ausführung erkennen.
Was läuft nun im Programm ab?
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
return 0;
}
// listing1: HelloWorld.cpp
In diesem Beispiel nutzen wir schon die erste Funktion aus der C++-Standardbibliothek. std::cout
ist die Standardausgabe, verbunden mit dem Monitor. Damit wird dir eine simple Möglichkeit geboten, um Daten unkompliziert auszugeben.
Achtung, ich habe bewusst die Formulierung „verbunden mit“ verwendet. Ausgaben beschränken sich nicht nur auf den Monitor. Du kannst die Standardausgabe auch mit anderen Ausgabegeräten verbinden. Trage deshalb keine Scheuklappen und vermeide einen Tunnelblick. In der Regel ist das Standardausgabegerät dennoch der Bildschirm.
Der Prefix std::
zeigt dir, dass sich die Funktion im Namenspace der Standardbibliothek befindet. Wenn dir die Beduetung gerade entfallen ist, dann schau dir einfach eps1.2_DasSkelett an.
Alles muss fließen
cout
steht für standard output stream und bildet eine Instanz der ostream Klasse. Die angezeigten Daten fügst du unter Verwendung des Operators <<
in diesen Stream ein.
Für Ein- und Ausgaben sequentieller Medien, wie beispielsweise der Bildschirm, deine Tastatur oder generell Dateien, nutzt C++ die recht praktikable Abstraktion der Streams. Nun, wie kannst du dir einen Stream am besten vorstellen? Es ist ein Gebilde aus aufeinander folgenden Zeichen, die du entweder herausziehen oder weitere hinzufügen kannst. Wichtig zu verstehen ist, dass ein Stream sowohl Quelle als auch Zielort für Characters darstellt und diese sequentiell bereitstellt oder entgegennimmt.
Die STL definiert ein paar Stream Objekte:
Stream | Beschreibung |
---|---|
cin | standard input stream |
cout | standard output stream |
cerr | standard error (output) stream |
clog | standard logging (output) stream |
In anderen Blogeinträgen werden dir hin und wieder cout
oder cin
begegnen. cerr
und clog
sind ebenfalls Output Streams und funktionieren grundsätzlich wie cout
. Der einzige Unterschied ist, dass die beiden bestimmte Anwendungsfälle hervorheben sollen: Error oder Logging Nachrichten.
Hier geht’s rein
Der logische nächste Schritt wäre, sich nicht nur Informationen anzeigen zu lassen und passiver Beobachter zu sein, sondern aktiv mit dem System zu interagieren. Damit würden wir über eine zweiseitige Kommunikationsschnittstelle interaktiv Informationen austauschen. Den Fachbegriff für eine Schnittstelle zur Kommunikation von Mensch und Computer kennst du mit Sicherheit: User Interface (UI).
Um einen oder mehrere Character einem Stream hinzuzufügen, kannst du den standard input stream cin
verwenden.
cin
ist eine Instanz der istream Klasse und lässt dich die Eingaben eines standardisierten Eingabegeräts einlesen. Häufig ist deine Tastatur dieses Eingabegerät. Der Extraction Operator >>
nimmt entnimmt dem cin
Stream Elemente, die du über die Tasten eintippst.
Für die korrekte Syntax schreibst du cin
zusammen mit dem Extraction Operator >>
. Anschließend folgt die Variable, in der du die Daten des Input Streams speichern möchtest (siehe listing2).
int value;
cin >> value;
// listing2: input of an integer value
Zunächst wird die Integer Variable value
deklariert. Danach werden die Werte aus dem Input Stream cin
in value
gespeichert. Doch welche Werte sind in diesem Stream? Wo kommen die Daten her?
cin
ist direkt mit deiner Tastatur verbunden und wartet auf deine Eingaben. Der Stream besteht also aus jeder Tasteninformation, die du drückst. Beendet wird die Sequenz mit der Enter Taste. Aber keine Hektik. cin
gibt dir alle Zeit, die du für die Eingabe benötigst. Sobald der Extraction Operator >>
im Quellcode erreicht wird, wartet das Programm, bis du deine Eingabe selbst abschließt.
Der Extration Operator schaut auf den Datentypen der ihm folgenden Variablen und interpretiert die Daten im Stream als solche. In listing2 erwartet er demnach Ganzzahlen.
Problematisch wird das spätestens, wenn der Operator die Eingabe nicht als Integer interpretieren kann. Dann schlägt die Extraction fehl und das Programm fährt fort, ohne Daten der Variablen zuzuweisen. value
bleibt dann leer.
Nicht ganz so schwerwiegend, dennoch nicht gewollt, ist der Fall, in dem interpretiert werden kann. Gibt der Benutzer in Listing2 zum Beispiel die Floating Point Zahl 3,7 ein, werden die Nachkommastellen gestrichen und value
hat den Wert 3.
Du hast auch die Möglichkeit, mehrere Eingaben aneinander zu reihen. Bei der Eingabe trennst du die beiden Werte entweder mit einem Leerzeichen oder mit Enter.
cin >> a >> b;
// listing3: chained statements
Du siehst, dass die Eingabe über Standardschnittstellen mit Hilfe von cin
ziemlich einfach ist. Doch du musst vorsichtig sein, wenn es darum geht, was der Benutzer eingeben kann und soll.
Come in and cout
Bis hierher haben wir wieder einiges gelernt. Jetzt wollen wir den ganzen Input und Output Kram auch in Aktion sehen.
Ein kleines Beispiel:
#include <iostream>
int main()
{
char firstLetter;
float floatNumber;
int intNumber;
std::cout << "Hi, what is the first letter of your name?" << std::endl;
std::cin >> firstLetter;
std::cout << "And now, please tell me a number between 2.0 and 3.0" << std::endl;
std::cin >> floatNumber;
intNumber = floatNumber;
std::cout << "Hey " << firstLetter << ", be careful with the data types, otherwise your " << floatNumber << " will quickly turn into a " << intNumber << "!" << std::endl;
return 0;
}
// listing4: input of an integer value
Alle Datentypen und die implizite Datenkonvertierung in Listing4 haben wir im letzten Blogeintrag kennengelernt. Also nichts Neues. Zuerst werden in der main()
Funktion drei Variablen mit den Datentypen char
,float
und int
deklariert.
Darauf folgt die erste Ausgabe auf der Konsole, die dich auffordert, einen Buchstaben einzutippen. Der Input Stream wartet auf deine Eingabe und speichert diese nach deiner Bestätigung mit Enter in firstLetter
.
Anschließend darfst du dir eine Zahl zwischen 2 und 3 aussuchen. Nachdem du deine Zahl in den Stream eingetragen hast und der Stream geschlossen wird, befindet sich dieser Wert in der Variablen floatNumber
.
Danach folgt eine ziemlich unschöne Zuweisung von floatNumber
an intNumber
. Bei dieser impliziten Konvertierung einer Floating Point Variable in eine Interger Variable sind die Nachkommastellen der Zahl verloren gegangen.
Du findest in vielen Programmen häufig Ein- und Ausgaben. Sie helfen dir dabei besser zu verstehen, wie die Programme im Detail funktionieren und wie sie Daten verarbeiten. Es ermöglicht dir auch, eigene Programme auf Fehler hin zu überprüfen, da so eine einfache Kontrolle deines Codes möglich ist.
endl vs. \n
Dieser Unterschied fällt unter die Kategorie “gut zu wissen…”. Machmal wirst du anstelle von std::endl
am Ende eines Output Streams "\n"
finden. Auf dem ersten Blick scheinen beide die selbe Funktion zu erfüllen. Natürlich gibt es ein „Aber“.
Der Unterschied liegt in einem kleinen Detail. std::endl
beendet nicht nur eine Zeile, sondern entnimmt alle Daten aus dem Stream Buffer. Jede Eingabe in einen Stream wird zunächst gebuffert. Alle Daten, die bis zur Ausgabe des Buffers eingegangen sind, werden aufeinmal ausgegeben.
Willst du nicht warten, bis der Buffer sich leert, kannst du ihn mit dem flush
Befehl dazu bringen. std::endl
hat die selbe Funktion wie "\n" << std::flush;
std::cout << std::endl // inserts a new line and flushes the stream
std::cout << "\n" // only inserts a new line.
// listing5: endl or \n
Wenn du also nur eine neue Zeile beginnen möchtest, nimmt ruhig "\n"
. Bist du dir unsicher, wann die Daten aus dem Bufer gelesen werden, oder benötigst genau zu einem Zeitpunkt alle Bufferdaten, dann benutze std::endl
.
Das bleibt hängen
Heute haben wir uns mit Input und Output Streams beschäftigt. Du weißt nun, wie du Eingaben deiner Tastatur mit std::cin >>
entgegennimmst und mit std::cout <<
wieder auf dem Bildschirm ausgeben lassen kannst. Zudem wissen wir jetzt, was Streams sind, wie wir eine neue Zeile anfangen (\n
) und wie wir den Stream Buffer ausspülen (std::flush
).
Ich wünsche dir maximalen Erfolg!
PS: Falls du dich jetzt nach dem Sinn des Lebens fragst, dann möchte ich dir dieses Buch empfehlen. Darin bekommst du eine Antwort mit Augenzwinkern. ;-)
English: The Hitchhiker’s Guide to the Galaxy - EAN 9781509886517
Deutsch: Per Anhalter durch die Galaxies - ISBN 978-3-0369-5954-2
Quellen
- [1] B. Stroustrup, A Tour of C++. Pearson Education, 2. Auflage, 29. Juni 2018.
- [2] B. Stroustrup, Programming: Principles and Practice Using C++. Addison Wesley, 2. Auflage, 15. Mai 2014.
- [3] U. Breymann, Der C++ Programmierer. C++ lernen – professionell anwenden – Lösungen nutzen. Aktuell zu C++17. München: Carl Hanser Verlag GmbH & Co. KG; 5. Auflage, 6. November 2017