C++ Kurs

Streamausgabe cout

Die Themen:

Ausgabestream cout
Ausgabe von Text und Zeichen
Escape-Sequenzen
Ausgabe von Daten (Zahlen)
Dezimale, hexadezimale und oktale Ausgabe
Manipulatoren
Beispiel und Übung

Ausgabestream cout

In dieser Lektion erfahren Sie, wie Sie etwas auf die Standardausgabe ausgeben. Da uns bis jetzt noch die Behandlung der Datentypen fehlt, wir aber auch die Ausgabe von Daten an dieser Stelle uns ansehen werden, werden wir nur ein paar einfache Datentypen für die Ausgabe verwenden.

Wenn Sie über Streams im Allgemeinen eine kurze Übersicht erhalten wollen, klicken Sie das Symbol links an.

Für die Ausgabe auf die Standardausgabe (dies ist in der Regel der Bildschirm) wird das Ausgabestream-Objekt cout verwendet. Damit der Compiler aber das cout Ausgabestream-Objekt kennt, müssen Sie eine entsprechende Datei, die so genannte Include- oder Header-Datei, in Ihr Programm einbinden. Die Datei, die Sie für cout einbinden müssen, besitzt den Namen iostream. Das Einbinden der Datei erfolgt durch die Präprozessor-Direktive #include <iostream>.


// Datei iostream einbinden
#include <iostream>

int main ()
{
   std::cout [<< ausgabe1...];
}

Beachten Sie, dass am Ende der Präprozessor-Direktive kein Semikolon steht! Mehr zu den Präprozessor-Direktiven, die übrigens alle mit dem Zeichen '#' beginnen, später noch im Kurs.

Die eigentliche Ausgabe erfolgt dann mit der Anweisung std::cout. Die allgemeine Syntax für die Ausgabe mittels cout lautet:

std::cout << ausgabe1 [ << ausgabe2 [ << ausgabe3 ...]];

Der Präfix std:: teilt dem Compiler mit, dass das Ausgabestream-Objekt im Namensraum std zu finden ist. Beachten Sie hier bitte, dass nach std zwei Doppelpunkte folgen. Auch zu Namensräumen später im Kurs noch mehr. Vorläufig können Sie sich unter einem Namensraum einen getrennten Bereich vorstellen, in dem Namen von z.B. Funktionen oder Variablen (Daten) definiert werden. Und jeder Name in einem solchen Bereich ist unabhängig von den Namen in anderen Bereichen, d.h. verschiedene Bereiche können gleiche Namen enthalten ohne dass dies zu einer Doppeldeutigkeit führt.

Anstelle nun bei jeder Ausgabe den Präfix std:: für den Namensraum anzugeben, stehen Ihnen auch noch folgende zwei Alternativen zur Verfügung:

1. Alternative:

Sie können einmal am Anfang des Programms, nach den #include-Anweisungen und vor main(...), die using-Anweisung angeben.

using std::cout;

Dadurch teilen Sie dem Compiler mit, dass er standardmäßig das Ausgabestream-Objekt cout aus dem erwähnten Namensraum std verwenden soll.


// Datei iostream einbinden
#include <iostream>

// using Anweisung
using std::cout;

int main ()
{
   cout [<< ausgabe1...];
}

2. Alternative

Als zweite Alternative können Sie die using-Directive

using namespace std;

verwenden. Diese Anweisung blendet den kompletten Namensraum std ins Programm ein, d.h. auf alles, was im Namensraum std enthalten ist, können Sie dann ohne explizite Angabe von std:: zugreifen.


// Datei iostream einbinden
#include <iostream>

// using Dircetive
using namespace std;

int main ()
{
   cout [<< ausgabe1...];
}

Die 2. Alternative sollten Sie in 'realen' Programmen nur dann einsetzen, wenn Sie sich über deren Auswirkung voll im Klaren sind. Ansonsten kann es unliebsamen Überraschungen durch Doppeldeutigkeit von Namen kommen. In den kleinen Beispielen im Kurstext wird diese Anweisung einfach aus Bequemlichkeitsgründen verwendet (oder ganz weggelassen). In den Beispielen im Kurs wird die using-Directive nicht eingesetzt. Vermeiden Sie auch in Ihren Übungen die using-Directive..


ACHTUNG! Die mittels #include einzubindende Datei iostream besitzt keine Extension .h, wie manchmal in anderen (leider auch neueren) Quellen noch angegeben.

Ausgabe von Text und Zeichen

Sollen Texte (bestehend aus mehreren Zeichen, auch als Strings bezeichnet) ausgegeben werden, so folgt nach dem Streamobjekt cout, wie bereits erwähnt, zunächst der Operator << . Im Anschluss an diesen Operator folgt dann der auszugebende Text, der in Anführungszeichen einzuschließen ist. Mehrere Texte können durch entsprechende Wiederholungen des Operators << und Textes ausgegeben werden. Am Ende einer cout-Anweisung wird kein automatischer Zeilenvorschub eingefügt. Wollen Sie einen Text in einer neuen Zeile beginnen lassen, so müssen Sie Escape-Sequenzen in den Text einfügen. Aber dazu kommen wir gleich noch. Anstatt einer Escape-Sequenz für den Zeilenumbruch können Sie auch den Manipulator endl in den Ausgabestream einfügen (siehe erste Ausgabe im Beispiel). Auch der Manipulator endl liegt im Namensraum std.

Außer Strings können Sie auch einzelne Zeichen ausgeben. Dazu ist das auszugebende Zeichen in Hochkomma einzuschließen. Selbstverständlich könnten Sie auch ein einzelnes Zeichen in Anführungszeichen einschließen, also z.B. anstatt 'A' auch "A" schreiben. Dies würde aber, vereinfacht ausgedrückt, zu etwas umständlicherem Code führen letztendlich.


// IO-Stream Datei einbinden
#include <iostream>

// cout und endl aus std Namensraum
using std::cout;
using std::endl;

// Das Programm
int main ()
{
   // Ausgabe eines einzelnen Textes mit Zeilenvorschub
   cout << "Aber Hallo!" << endl;
   // Ausgabe mehrerer Texte
   cout << "Mein " << " erstes"
           << " Programm";

   // Einzelne Zeichen ausgeben
   cout << '!' << '?';
   // und fertig!
}

Aber Hallo!
Mein erstes Programm!?

Beachten Sie im Beispiel, dass die zweite cout-Anweisung über 2 Zeilen geht. Sie wissen ja, erst das Semikolon schließt eine Anweisung ab!

Escape-Sequenzen

Sehen wir als Nächstes an, wie nicht-druckbare Zeichen (z.B. ein Zeilenvorschub oder auch ein Tabulator) ausgegeben werden. Hierfür stehen verschiedene Steueranweisungen, so genannte Escape-Sequenzen, zur Verfügung. Diese Escape-Sequenzen können an beliebiger Stelle in einem Text (eingeschlossen in Anführungszeichen) oder aber als einzelnes Zeichen (eingeschlossen in Hochkomma) in einer cout-Anweisung stehen. Sie beginnen immer mit dem Backslash-Zeichen \ gefolgt von ein ASCII-Zeichen, das die auszuführende 'Operation' beschreibt.

Die nachfolgende Tabelle enthält alle verfügbaren Escape-Sequenzen.

Escape-Sequenz Ausgabe von
\a Alarmton (Beep)
\b Backspace
\n Zeilenvorschub
\r Return (Zeilenanfang)
\f Formfeed (neue Zeile)
\t horizontaler Tabulator
\v vertikaler Tabulator
\\ Das Zeichen \ selbst
\" Anführungszeichen
\' Hochkomma
\? Fragezeichen
\xhhh 1- bis 3-stellige Hexadezimalzahl
\ooo 1- bis 3-stellig Oktalzahl

Die Bedeutung und Wirkungsweise der meisten Escape-Sequenzen dürfte aus der Beschreibung hervorgehen. Beachten Sie bei den Escape-Sequenzen \" und \' im Programmbeispiel wann diese benötigt werden. Innerhalb eines Strings muss das Zeichen " als Escape-Sequenz definiert werden, da es standardmäßig den auszugebenden Text begrenzt. Das Zeichen ' benötigt hier keine Escape-Sequenz. Genau andersherum verhält es sich, wenn Sie ein einzelnes Zeichen ausgeben, da einzelne Zeichen in ' eingeschlossen werden.

Je nach verwendetem Betriebssystem werden einiger dieser Steuerzeichen, insbesondere \f und \v, als Sonderzeichen dargestellt. Dies liegt aber nicht an der Sprache C++ bzw. Ihrem Compiler, sondern an der Standardausgabe. Diese ist dann nicht in der Lage, die entsprechenden Operationen auszuführen.

Vielleicht verwirren mag am Anfang die Escape-Sequenz \?, da Sie ja ein Fragezeichen auch direkt innerhalb eines Textes oder als einzelnes Zeichen ausgeben können. Die Ursache für diese Escape-Sequenz liegt in Steinzeit der Programmierung. Zum damaligen Zeitpunkt enthielten nicht alle Tastaturen die für ein C bzw. C++ Programm notwendigen Sonderzeichen wie z.B. [ oder }. Um aber auch mit diesen Tastaturen C Programme schreiben zu können, wurden die Trigraphen eingeführt. Ein Trigraph besteht dabei aus 3 Zeichen, wobei die ersten beiden Zeichen Fragezeichen sind und das dritte Zeichen das Sonderzeichen bestimmt. Sie können sich dies im nachfolgenden Beispiel einmal ansehen, indem Sie zusätzlich ein einem String ausgeben in dem die Zeichenfolge ??! enthalten ist. Anstelle der Zeichenfolgen ??! werden Sie das Sonderzeichen | erhalten. Trigraphen haben aber in der heutigen Zeit keine Bedeutung mehr und sind nur wegen der Abwärtskompatibilität im C++ Standard enthalten.

Wenn das nebenstehende Symbol anklicken können Sie sich ein kleines Beispielprogramm ansehen, welches die Wirkungsweise der verschiedenen Escape-Sequenzen demonstriert. Wenn Sie dieses übersetzen wollen, erstellen Sie sich wie gewohnt ein entsprechendes leeres Projekt und kopieren dann den Quellcode in die Quellcode-Datei des Projekts.

Ausgabe von Daten (Zahlen)

Um numerische Daten auszugeben, werden diese, genauso wie Strings, mit dem Operator << an das Ausgabestream-Objekt cout übergeben. Dabei spielt der Datentyp (wird in der nächsten Lektion erklärt) des auszugebenden Datums zunächst keine Rolle, d.h. Sie können auf diese Art sowohl Ganzzahlen wie auch Gleitkommazahlen ausgeben. Ebenso können innerhalb einer cout-Anweisungen Texte und Daten beliebig gemischt werden. Beachten Sie im Beispiel, dass die cout-Anweisungen teilweise über mehrere Zeilen gehen!


// IO-Stream Datei einbinden
#include <iostream>

// cout aus std Namensraum
using std::cout;

// Das Programm
int main ()
{
   // Auszugebende Daten
   int anyVal = 10;
   char byteVal = 66;
   float floatVal = 1.23f;

   // Gemischte Ausgabe von Text und Daten
   cout << "int-Datum: " << anyVal << " float-Datum: "
        << floatVal << '\n';
   // Ausgabe von char-Daten
   cout << "char-Datum: " << byteVal << '\n';
   cout << "char-Datum als Wert: "  
        <<  static_cast<int>(byteVal);
   // und fertig!
}

int-Datum: 10 float-Datum: 1.23
char-Datum: B
char-Datum als Wert: 66

Für die Ausgabe der Daten werden standardmäßig nur so viele Stellen verwendet, wie die Daten benötigen. Die Ausgabe von Ganzzahlen erfolgt als Dezimalzahl und Gleitkommazahlen werden je nach Wert mit oder ohne Exponenten dargestellt. Wie Sie die Ausgabe von numerischen Daten formatieren können, das erfahren Sie gleich noch.

Stören Sie sich bitte im Augenblick nicht an den ersten drei Anweisungen in der Funktion main(). Hier werden 3 Variablen für die Ausgabe definiert und initialisiert. Mehr zur Definition von Variablen erfahren Sie gleich in der nächsten Lektion. Anstelle von Variablen hätten auch direkt die Werte, also 10, 66 und 1.23, in der cout-Anweisung ausgeben können.

Werden char, signed char oder unsigned char Daten ausgegeben, so erfolgt die Ausgabe standardmäßig als ASCII-Zeichen, d.h. der Hex-Wert 0x41 wird als Buchstabe 'A' ausgegeben. Wollen Sie char-Daten als numerischen Wert ausgeben, so müssen Sie vor dem Datum eine Typkonvertierung z.B. in den Datentyp int angeben. Siehe auch letzte cout-Anweisung im Beispiel oben.

Mehr zu Typkonvertierungen später noch im Kurs.


Wenn Sie neugierig sind, können Sie sich nun auch einmal die Tabelle der ASCII-Code ansehen.

Dezimale, hexadezimale und oktale Ausgabe

In manchen Fällen kann es durchaus sinnvoll sein, Ganzzahlen in einem anderen Zahlensystem als dem standardmäßigen Dezimalsystem darzustellen. Um Ganzzahlen als hexadezimal oder oktal Zahl auszugeben, stehen  so genannte Manipulatoren zur Verfügung, die einfach an der entsprechenden Stelle in den Ausgabestream eingefügt werden.

Folgende Manipulatoren stellen die Ausgabe von Ganzzahlen auf das hexadezimale, oktale oder dezimale Zahlensystem um:

Manipulator Ausgabebasis
std::dec dezimal (Basis 10)
std::hex hexadezimal (Basis 16)
std::oct oktal (Basis 8)

Die Manipulatoren können alternativ auch mit der using-Anweisung, z.B. using std::hex, aus den std-Namensraum eingebunden werden. In diesem Fall können Sie die Namensraumangabe in der cout-Anweisung weglassen (siehe auch nachfolgendes Beispiel).


// IO-Stream Datei einbinden
#include <iostream>

// cout und hex-Manipulator aus std Namensraum
using std::cout;
using std::hex;

// Das Programm
int main ()
{
   // Auszugebende Daten
   int var = 10;
   // Zahlenbasis mit ausgeben
   cout << std::showbase;
   cout << " Dez: " << var;
   cout << " Hex: " << hex << var;
   cout << " Okt: " << std::oct << var;
   cout << " Zahl: " << var;
}

 Dez: 10 Hex: 0xa Okt: 012 Zahl: 012


Wenn Sie das hexadezimale und oktale Zahlensystem noch nicht kennen, dann können Sie jetzt links das Symbol anklicken um eine kleine Einführung in diese Zahlensysteme zu erhalten

Eine einmal eingestellte Zahlenbasis für die Ausgabe bleibt so lange aktiv, bis sie explizit umgestellt wird.

Bei der Ausgabe sollten Sie allerdings beachten, dass standardmäßig keinerlei Kennung für die aktuelle Zahlenbasis (wie z.B. 0x für Hex-Zahlen.) der Zahl automatisch vorangestellt wird. Die Darstellung der Zahl 10 kann damit sowohl 10 (Ausgabe in dezimal), 16 (Ausgabe in hexadezimal) oder 8 (Ausgabe in oktal) bedeuten. Damit bei der Ausgabe die Zahlenbasis ersichtlich wird, sollten Sie noch den Manipulator std::showbase mit in den Ausgabestream einfügen (siehe Beispiel oben). Die ausgegebenen Werte erhalten dann folgende Kennungen:

Zahlensystem Kennung
dezimal keine Kennung
hexadezimal 0x oder 0X
oktal 0 (null)

Lesen Sie in der Ausgabe z.B. 0x10, so bedeutet dies eine hexadezimal 10 (gleich 16 dezimal). Besonders beachten Sie müssen oktale Ausgaben! Die Ausgabe 0100 bedeutet eine oktale 100, und entspricht damit 64 dezimal.

Manipulatoren

Außer den eben vorgestellten Manipulatoren dec, hex und oct stehen unter anderem noch die Manipulatoren setbase(...), setw(...), setfill(...), setprecision(...), fixed und scientific zur Verfügung, die ebenfalls im Namensraum std liegen. Wenn Sie einen dieser Manipulatoren einsetzen, müssen Sie die Präprozessor-Directive #include <iomanip> zusätzlich im Programm angeben.

setbase

Beginnen wir mit dem Manipulator setbase(n). Er bietet prinzipiell nichts Neues. setbase(n) dient, genauso wie dec, hex und oct, zur Einstellung des Zahlensystems für die Ausgabe. Der Parameter n gibt das entsprechende Zahlensystem an und kann die Werte 8, 10 und 16 für das Oktal-, Dezimal- und Hexadezimal-System annehmen. Alle anderen Werte stellen die Ausgabe wieder auf das Dezimalsystem zurück.


// IO-Stream und Manipulatoren einbinden
#include <iostream>
#include <iomanip>

using std::cout;
using std::setbase;

// Das Programm
int main ( )
{
    // Auszugebendes Datum
    int var = 10;
    // Ausgabe als Hex-Zahl
    cout << setbase(16) << var << "->";
    // Ausgabe als Oktal-Zahl
    cout << setbase(8) << var << "->";
    // Ausgabe wieder als Dezimal-Zahl
    cout << setbase(10) << var;
}

a->12->10

Die eingestellte Zahlenbasis bleibt so lange gültig, bis sie explizit umgestellt wird. Außerdem wirkt setbase(n) nur auf Ganzzahlen.

setw

Mit dem Manipulator setw(n) kann die minimale Breite des nachfolgenden Ausgabefeldes eingestellt werden. Der Parameter n legt die Anzahl der minimalen Ausgabestellen. Benötigt die Ausgabe mehr Stellen als angegeben wurde, so wird das Ausgabefeld entsprechend vergrößert, d.h. die Zahl wird immer vollständig dargestellt. Die Ausgabe in diesem Ausgabefeld erfolgt standardmäßig rechtsbündig. Wie Sie die Ausgabe auf linksbündig umstellen können, können Sie am Ende dieser Lektion unter der Beschreibung der Memberfunktion setf(...) nachlesen.

Die Angabe von setw(n) gilt nur für die unmittelbar nachfolgende Ausgabe (siehe Beispiel)!



// IO-Stream Datei und
// Manipulatoren einbinden

#include <iostream>
#include <iomanip>

using std::cout;
using std::setw;

// Das Programm
int main ( )
{
    // Auszugebendes Datum
    int var = 10;
    // Datum ohne explizite Feldbreite ausgeben
    cout << ":" << var << ":";
    // Feldbreite für ':' auf mindestens 4 setzen
    cout << setw(4) << ":" << var << ":";
    // Feldbreite für var auf mindestens 4 setzen
    cout << ":" << setw(4) << var << ":";
    // Ausgabe wieder ohne explizite Feldbreite
    cout << ":" << var << ":";
}

:10:~~~:10::~~10::10:

Hinweis: Das Zeichen ~ steht hier für ein Leerzeichen!

Der Manipulator setw wirkt sowohl auf Ganzzahlen wie auch auf Gleitkommazahlen.

setfill

Ist die Breite des Ausgabefeldes größer als tatsächlich Stellen benötigt werden, so können nicht belegte Stellen mit einem beliebigen Zeichen ausgefüllt werden. Die Festlegung des Füllzeichens erfolgt mit dem Manipulator setfill(n). Er erhält als Parameter n das zu setzende Füllzeichen.


// IO-Stream Datei und
// Manipulatoren einbinden

#include <iostream>
#include <iomanip>

using std::cout;

// Das Programm
int main ( )
{
    // Auszugebendes Datum
    int var = 10;
    // Ausgaben mit Füllzeichen '#'
    cout << ":" << std::setw(4) << std::setfill('#') << var << ":";
    cout << ":" << std::setw(3) << var << ":";
    // Füllzeichen wieder zurückstellen
    cout << ":" << std::setw(4) << std::setfill(' ') << var << ":";
}

:##10::#10::~~10:

Hinweis: Das Zeichen ~ steht hier für ein Leerzeichen.

Beachten Sie, dass Sie hier ein Zeichen übergeben müssen, welches in Hochkomma eingeschlossen wird.

Wie Sie vielleicht schon vermutet haben, ist das Standard-Füllzeichen das Leerzeichen. Ein einmal eingestelltes Füllzeichen bleibt so lange gültig, bis es durch ein anderes ersetzt wird. setfill wirkt ebenfalls auf alle Datentypen.

Im Beispiel oben wurde der setfill Manipulator übrigens diemal mit der vollen Qualifikation std::setfill(...) verwendet.

setprecision und fixed/scientific

Für die Ausgabe von Gleitkommazahlen können Sie über den Manipulator setprecision(n) die Anzahl der auszugebenden Stellen (ohne Vorzeichen und einem eventl. Exponenten) einstellen. Überschreitet die Anzahl der Vorkommastellen die mit setprecision eingestellte Stellenanzahl, so wird automatisch auf Exponentialdarstellung umgestellt (erste Ausgabe im nachfolgenden Beispiel). Wird über den Manipulator fixed oder scientific die Darstellung ohne oder mit Exponenten erzwungen, so legt setprecision die Anzahl der Nachkommastellen fest.


// IO-Stream Datei und
// Manipulatoren einbinden

#include <iostream>
#include <iomanip>

using std::cout;
using std::setprecision;
using std::fixed;

// Das Programm
int main ( )
{
    // Auszugebende Daten
    double var1 = 40000.0/3.0;
    double var2 = 4.0/3.0;
    // Ausgabe auf 4 Stellen begrenzen
    cout << setprecision(4);
    // Normale Ausgabe
    cout << var1 << ' ' << var2 << "->";
    // Ausgabe immer ohne Exponenten
    cout << fixed;
    cout << var1 << ' ' << var2;
}

1.333e+004 1.333->13333.3333 1.3333

Und auch die einmal eingestellte Anzahl der auszugebenden Stellen bleibt so lange gültig, bis sie erneut umgesetzt wird. Standardmäßig beträgt die Genauigkeit für die Ausgabe 6 Stellen.

Um die Ausgabe  einer Gleitkommazahl im Festkommaformat zu erzwingen, wird der Manipulator fixed verwendet. Er wird genauso wie z.B. der Manipulator hex einfach in den Ausgabestream eingefügt. Alle Gleitkommazahlen werden danach so lange im Festkommaformat ausgegeben, bis die Ausgabe durch den Manipulator scientific auf Exponentialdarstellung umgestellt wird.

Sie können sich noch weitere Informationen zur Ausgabe ansehen, wenn Sie in nachfolgender Liste das entsprechende Symbol anklicken.

Formatierungsflags: Low-Level Kontrolle über den Ausgabestream cout und (wird später noch erklärt) den Eingabestream cin.

cout Pufferung: Erläutert kurz die gepufferte Ausgabe von cout.

cerr und clog: außer dem Ausgabestream cout gibt noch zwei weitere Streams für die Ausgabe, die Streams cerr und clog

Ansonsten folgt jetzt das erste 'größere' Beispiel im Kurs und auch Ihre erste Übung.

Beispiel und Übung

Beispiel:

Das Programm gibt zunächst die unten dargestellte Anschrift  aus.

Anschließend werden zwei Zeilen mit je drei Strings in Tabellenform dargestellt. Als 'Spaltentrenner' wird ein Tabulator verwendet.

Zum Schluss erfolgt die Ausgabe eines Alarmtons (Bing!).


Karl Mueller
Sackgasse 23
12345 Astadt
============

Eins Zwei Drei
Vier Fuenf Sechs
(Beep)


// C++ Kurs
// Beispiel zu cout

// Zuerst Dateien iostream und iomanip einbinden

#include <iostream>
// std Namensraum benutzen für
using std::cout;
using std::endl;

// main() Funktion
int main ()
{
   // Anschrift ausgeben
   cout << "Karl Mueller\nSackgasse 23\n";
   cout << "12345 Astadt" << endl;
   cout << "============\n\n";

   // Tabelle ausgeben
   cout << "Eins\tZwei\tDrei\n";
   cout << "Vier\tFuenf\tSechs\n";
   cout << "\a";
}

Übung:

Verwenden Sie in dieser Übung keine using-Anweisung und auch keine using-Directive!

Definieren und initialisieren Sie das Datum value und number wie folgt:

double val = 100.0 / 3.0
int number = 10;

Geben Sie zuerst das Datum val dann mit 10 Stellen aus, wobei die nicht belegten Stellen mit dem Zeichen '*' aufzufüllen sind.

Geben Sie das Datum number als Hexadezimal-, Oktal- und Dezimalzahl aus. Bei der Ausgabe soll die Kennung für die aktuelle Zahlenbasis mit ausgegeben werden.


100/3 = ***33.3333
10 im 16er, 8er und 10er System:
Hex: 0xa, Okt: 012, Dez: 10

Lösung ansehen