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 cinin 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,floatund 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