C++ Kurs

Ausgabestream cout

Die Themen:

Ausgabestream cout

Diese KApitel behandelt die Ausgabe von Texten und Daten auf die Standardausgabe. Da bis jetzt noch die Behandlung der Datentypen fehlt, wir uns aber auch die Ausgabe von Daten an dieser Stelle ansehen wollen, werden wir nur ein paar einfache Daten für die Ausgabe verwenden.

DetailWenn 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, muss eine entsprechende Datei, die sogenannte Include- oder Header-Datei, in das Programm eingebunden werden. Dieser erfolgt durch die Präprozessor-Direktive #include <iostream>.

PgmHeader// Datei iostream einbinden
#include <iostream>

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

Dabei ist zu beachten, 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.

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

std::cout << AUSGABE1 [ << AUSGABE2 [ << AUSGABE3 ...]];

Das Präfix std:: teilt dem Compiler mit, dass das Ausgabestream-Objekt cout aus dem Namensraum std zu verwenden ist. Ein Namensraum ist prinzipiell ein gesonderter Bereich, in dem Namen z.B. von Funktionen oder Daten definiert werden. Und jeder Name in einem solchen Namensraum ist unabhängig von Namen in anderen Namensräumen, d.h. verschiedene Namensräume können durchaus gleiche Namen enthalten, ohne dass dies zu einer Doppeldeutigkeit führt. Auch die Namensräume werden später in einem eigenen Kapitel noch behandelt.

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

1. Alternative:

Nach der #include-Anweisung und vor main() kann die nachfolgende using-Anweisung gestellt werden.

using std::cout;

Diese Anweisung teilt dem Compiler mit, dass er standardmäßig das Ausgabestream-Objekt cout aus dem Namensraum std verwenden soll.

PgmHeader
// Datei iostream einbinden
#include <iostream>

// using Anweisung
using std::cout;

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

2. Alternative

Als zweite Alternative kann die using-Directive

using namespace std;

verwendet werden. Diese Anweisung blendet den kompletten Namensraum std ein, d.h. auf alles, was im Namensraum std enthalten ist, kann dann ohne die explizite Angabe von std:: zugegriffen werden.

PgmHeader
// Datei iostream einbinden
#include <iostream>

// using Directive
using namespace std;

int main ()
{
   cout [<< ausgabe1...];
}
HinweisDie 2. Alternative sollten Sie in 'realen' Programmen nur dann einsetzen, wenn Sie sich über deren Auswirkung genau im Klaren sind. Ansonsten kann es zu unliebsamen Überraschungen durch Doppeldeutigkeit von Namen kommen. In den kleinen Beispielen innerhalb eines Kapitels wird diese Anweisung einfach aus Bequemlichkeitsgründen verwendet, oder auch ganz weggelassen. In den C++ Beispielen im Kurs wird die using-Directive nicht eingesetzt. Vermeiden Sie in Ihren Übungen die using-Directive.

Ausgabe von Text und Zeichen

Soll ein Text, auch als String bezeichnet und aus mehreren Zeichen bestehend, ausgegeben werden, so folgt nach dem Streamobjekt cout zunächst der Operator << . Im Anschluss an diesen Operator folgt dann der auszugebende String, welcher in Anführungszeichen einzuschließen ist. Mehrere Strings können durch entsprechende Wiederholungen des Operators << und der Strings ausgegeben werden. Am Ende einer Ausgabe wird kein automatischer Zeilenvorschub eingefügt. Soll ein Text in einer neuen Zeile stehen, so muss eine entsprechende Escape-Sequenz in den String eingefügt werden. Aber dazu kommen wir gleich noch. Anstelle einer Escape-Sequenz für den Zeilenumbruch kann der Manipulator std::endl in den Ausgabestream eingefügt werden (siehe erste Ausgabe im nachfolgenden Beispiel). Und auch der Manipulator endl liegt, wie zu sehen ist, im Namensraum std.

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

PgmHeader
// 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 String mit Zeilenvorschub
   cout << "Aber Hallo!" << endl;
   // Ausgabe mehrerer Strings
   cout << "Mein " << " erstes"
        << " Programm";
   // Einzelne Zeichen ausgeben
   cout << '!' << '?';
   // und fertig!
}
Programmausgabe 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

Für die Ausgabe von nicht-druckbaren Zeichen, wie z.B. ein Zeilenvorschub oder auch ein Tabulator, stehen verschiedene Steueranweisungen, sogenannte Escape-Sequenzen, zur Verfügung. Diese Escape-Sequenzen können an beliebiger Stelle in einem String oder aber als einzelnes Zeichen in einer cout-Anweisung stehen. Escape-Sequenzen beginnen immer mit einem Backslash-Zeichen \, gefolgt von einem ASCII-Zeichen, das die auszuführende 'Operation' beschreibt.

Die nachfolgende Tabelle enthält eine Übersicht über 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 deren Beschreibung hervorgehen. Beachten werden muss bei den Escape-Sequenzen \" und \' nur, 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 ein einzelnes Zeichen ausgegeben werden soll, da einzelne Zeichen in ' eingeschlossen werden.

HinweisJe nach verwendeter Umgebung werden einige 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.

Verwirren mag am Anfang vielleicht die Escape-Sequenz \?, da ein Fragezeichen auch direkt innerhalb eines Strings oder als einzelnes Zeichen ausgegeben werden kann. Der Grund für diese Escape-Sequenz liegt in der Urzeit der C-Programmierung. Zum damaligen Zeitpunkt enthielten nicht alle Tastaturen die für ein C-Programm notwendigen Sonderzeichen wie z.B. [ oder }. Um aber auch mit diesen Tastaturen C-Programme schreiben zu können, wurden Trigraphen eingeführt. Ein Trigraph besteht dabei aus 3 Zeichen, wobei die ersten beiden Zeichen Fragezeichen sind und das dritte Zeichen das Sonderzeichen bestimmt. Trigraphen haben aber in der heutigen Zeit keine Bedeutung mehr und sind nur der Abwärtskompatibilität wegen noch im C++ Standard enthalten.

BeispielWenn 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 im nächsten Kapitel erklärt) des auszugebenden Datums zunächst keine Rolle, d.h. auf diese Art können sowohl Ganzzahlen als auch Gleitkommazahlen ausgegeben werden. Ebenso können innerhalb einer cout-Anweisungen Strings und Daten beliebig gemischt auftreten.

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

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

// Das Programm
int main ()
{
   // Auszugebende Daten
   auto anyVal = 10;
   auto byteVal = (char)66;
   auto 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!
}
Programmausgabe int-Datum: 10 float-Datum: 1.23
 char-Datum: B
 char-Datum als Wert: 66

Für die Ausgabe der Daten werden standardmäßig 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 das Format für die Ausgabe von numerischen Daten explizit festgelegt werden kann, das folgt gleich noch.

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

AchtungWerden char, signed char oder unsigned char Daten ausgegeben, so erfolgt deren Ausgabe standardmäßig als ASCII-Zeichen, d.h. der Hex-Wert 0x41 wird als Buchstabe 'A' ausgegeben. Soll ein char-Datum als numerischer Wert ausgegeben werden, so muss das Datum in einen anderen Ganzzahl-Datentyp, z.B. in den Datentyp int, konvertiert werden. Siehe auch letzte cout-Anweisung im Beispiel oben. Mehr zu Typkonvertierungen später noch.
DetailWenn Sie neugierig sind, können Sie sich nun auch einmal die Tabelle der ASCII-Code ansehen.

Dezimale, hexadezimale und oktale Ausgabe

Manchmal kann es durchaus nützlich sein, Ganzzahlen in einem anderen Zahlensystem als dem standardmäßigen Dezimalsystem darzustellen. Um eine Ganzzahl als Hexadezimal- oder Oktal-Zahl auszugeben, stehen sogenannte 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 kann die Namensraumangabe in der cout-Anweisung weglassen werden (siehe auch nachfolgendes Beispiel).

PgmHeader
// 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
   auto var = 10;
   // Zahlenbasis mit ausgeben
   cout << std::showbase;   // Wird gleich noch beschrieben
   cout << " Dez: " << var;
   cout << " Hex: " << hex << var;
   cout << " Okt: " << std::oct << var;
   cout << " Zahl: " << var;
}
DOSHeader  Dez: 10 Hex: 0xa Okt: 012 Zahl: 012
DetailWenn Sie das hexadezimale oder oktale Zahlensystem noch nicht kennen, dann können Sie 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 gültig, bis sie explizit umgestellt wird. Dabei ist allerdings zu beachten, dass bei der Ausgabe standardmäßig keinerlei Kennung für die aktuelle Zahlenbasis mit ausgegeben wird, wie z.B. 0x für Hex-Zahlen. 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, sollte der Manipulator std::showbase mit in den Ausgabestream einfügt werden (siehe Beispiel oben). Die ausgegebenen Werte erhalten dann folgende Kennungen:

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

Wird beispielweise der Wert 0x10 ausgegeben, so bedeutet dies eine hexadezimale 10 (gleich 16 dezimal). Besondere Beachtung verdienen die oktalen 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, welche ebenfalls im Namensraum std liegen. Wenn einer dieser Manipulatoren eingesetzt wird, muss die Präprozessor-Directive #include <iomanip> zusätzlich im Programm mit angegeben werden.

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.

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

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

// Das Programm
int main ( )
{
    // Auszugebendes Datum
    auto 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;
}
Programmausgabe a->12->10

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

setw

Mit dem Manipulator setw(n) wird die minimale Breite des nachfolgenden Ausgabefeldes festgelegt. Der Parameter n gibt die Anzahl der Stellen an, die für die Ausgabe mindestens verwendet werden. Benötigt die Ausgabe mehr Stellen als angegeben wurden, so wird das Ausgabefeld entsprechend erweitert, d.h. die Zahl wird immer vollständig dargestellt. Die Ausgabe in diesem Ausgabefeld erfolgt standardmäßig rechtsbündig. Wie die Ausgabe auf linksbündig umgestellt werden kann, steht am Ende dieses Kapitels unter der Beschreibung der Memberfunktion setf(...).

AchtungDie Angabe von setw(n) gilt nur für die unmittelbar nachfolgende Ausgabe (siehe Beispiel)!
PgmHeader
// IO-Stream Datei und
// Manipulatoren einbinden

#include <iostream>
#include <iomanip>

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

// Das Programm
int main ( )
{
    // Auszugebendes Datum
    auto 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 << ":";
}
Programmausgabe :10:~~~:10::~~10::10:
Hinweis: Das Zeichen ~ steht hier für ein Leerzeichen!

Der Manipulator setw wirkt sowohl auf Ganzzahlen als auch auf Gleitkommazahlen und Strings.

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 verwendende Füllzeichen.

PgmHeader
// IO-Stream Datei und
// Manipulatoren einbinden

#include <iostream>
#include <iomanip>

using std::cout;

// Das Programm
int main ( )
{
    // Auszugebendes Datum
    auto 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 << ":";
}
Programmausgabe :##10::#10::~~10:
 Hinweis: Das Zeichen ~ steht hier für ein Leerzeichen.

Es ist zu beachten, dass hier ein Zeichen übergeben werden muss und kein String.

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

setprecision und fixed/scientific

Für die Ausgabe von Gleitkommazahlen kann durch den Manipulator setprecision(n) die Anzahl der auszugebenden Stellen, ohne Vorzeichen und einem eventl. Exponenten, eingestellt werden. Ü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.

PgmHeader
// 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;
}
Programmausgabe 1.333e+004 1.333->13333.3333 1.3333

Und auch hier bleibt die einmal eingestellte Anzahl der auszugebenden Stellen 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. 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 der nachfolgenden Liste das entsprechende links Symbol anklicken.

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

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

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


DetailUnd hier geht's jetzt zum Beispiel und zur Übung.