Standardausgabe
Ausgabestream cout
Für die Ausgabe auf die Standardausgabe, dies ist in der Regel der Bildschirm, wird im Allgemeinen der Ausgabestream cout aus der C++-Standardbibliothek verwendet.
Damit der Compiler cout kennt, ist eine Datei, die sogenannte Include- oder Header-Datei, einzubinden. Für cout ist dies die Datei iostream. Das Einbinden erfolgt durch die Präprozessor-Direktive
#include <iostream>
Dabei ist zu beachten, dass am Ende der Präprozessor-Direktive kein Semikolon steht! Mehr zu den Präprozessor-Direktiven, die alle mit dem Zeichen '#' beginnen, später im Kapitel Präpozessor-Direktiven.
Ab C++23 sollten anstelle von include-Anweisungen die import-Anweisung
import std;
stehen. Da außer MS Visual Studio fast kein Compiler diesen Import fehlerfrei durchführt, werden im weiteren Verlauf des Tutorials weiterhin include-Anweisungen verwendet.
Auszugebenden Texte und Daten werden mit dem Operator << in den Ausgabestream übertragen.
std::cout << AUSGABE1 [<< AUSGABE2 [<<...]];
Das Präfix std:: teilt dem Compiler mit, dass das Ausgabestream-Objekt cout im Namensraum der Standardbibliothek liegt. Mehr zu den Namensräumen ebenfalls später im Kapitel Namensräume.
Anstelle bei jeder Ausgabe das Präfix std:: anzugeben, kann vor der ersten Verwendung von cout die nachfolgende using-Anweisung eingefügt werden.
using std::cout
// Datei iostream einbinden
#include <iostream>
// using Anweisung
using std::cout;
int main ()
{
cout << ...; // hier steht dann die Ausgabe
}
Text- und Datenausgabe
Auszugebende Texte (Strings) und Daten werden durch Verkettung mit dem Operator << in den Ausgabestream übertragen, wobei Texte in Anführungszeichen eingeschlossen werden.
Am Ende einer Ausgabe erfolgt kein automatischer Zeilenumbruch. Soll nach einer Ausgabe eine neue Zeile begonnen werden, ist eine Escape-Sequenz auszugeben, die im nächsten Abschnitt erläutert wird.
#include <iostream>
int main()
{
// Eine Variable definieren und initialisieren
// Variablen werden im naechsten Kapitel behandelt
int var = 10;
// Ausgabe eines Textes und des Datums var
std::cout << "var hat den Wert " << var;
}
var hat den Wert 10
Für die Formatierung der Ausgabe stehen diverse Manipulatoren zur Verfügung, wie z.B. setw(n) um ein Datum mit n Stellen auszugeben. Auf der Seite https://en.cppreference.com ist unter dem Stichwort input/output manipulators eine Übersicht der Manipulatoren zu finden.
Formatierte Ausgaben
Im weiteren Verlaufe des Tutorials werden für die Formatierung der Ausgabe die neueren Bibliotheksfunktionen format(), print() und println() verwendet. format() legt die formatiert auszugebenden Texte und Daten in einem String-Objekt ab, welches dann mittels cout ausgegeben werden kann. print() bzw. println() geben die Daten direkt in einen Ausgabestream aus, wobei println() nach der Ausgabe einen Zeilenvorschub ausgibt und print() nicht.
Wird die Bibliotheksfunktion format() verwendet ist die Header-Datei format einzubinden und für die Bibliotheksfunktionen print() bzw. println() die Header-Datei print.
Die Funktionen besitzen folgende Syntax:
std::string std::format(std::format_string fmt
[,
Args&&... args]);
void std::print([std::FILE* stream,]
std::format_string fmt [,Args&&... args]);
void std::println([std::FILE* stream,]
std::format_string fmt [,Args&&... args]);
Der optionale erste Parameter stream bei print() bzw. println() legt den für die Ausgabe zu verwendenden Ausgabestream fest und ist in der Regel ein Dateistream (siehe Kapitel Schreiben in Datei). Wird er weggelassen, erfolgt die Ausgabe auf die Standardausgabe.
Der Parameter fmt ist ein in Anführungszeichen eingeschlossener Formatierungsstring. Er enthält den auszugebenden Text sowie die Platzhalter { } für die auszugebenden Daten. Enthält ein Text ebenfalls geschweifte Klammern, sind diese zu verdoppeln.
Der optionale letzte Parameter args ist eine kommaseparierte Liste mit den auszugebenden Daten. Dabei wird standardmäßig das erste Datum in der Liste dem ersten Platzhalter { } im Formatierungsstring zugewiesen, das zweite Datum dem zweiten Platzhalter usw.
Im nachfolgenden Beispiel erzeugen alle drei Anweisungen die gleiche Ausgabe.
#include <iostream>
#include <format>
#include <print>
int main()
{
// Eine Variable definieren und initialisieren
// Variablen werden im naechsten Kapitel behandelt
int var = 10;
// Ausgabe ueber einen String mittels format()
std::cout <<
std::format("1: var hat den Wert {}\n",var);
// Ausgabe mittels println, wobei der Ausgabestream
// std::cout explizit angegeben wird
std::println(std::cout,"2: var hat den Wert {}",var);
// Ausgabe mittels println mit implizitem std::cout
// Ausgabestream
std::println("3: var hat den Wert {}\n",var);
}
1: var hat den Wert 10
2: var hat den Wert 10
3: var hat den Wert 10
Die standardmäßige Zuordnung, Platzhalter zu Datum, kann durch Angabe eines Indexes innerhalb des Platzhalters überschrieben werden, wobei das erste Datum in der Liste den Index 0 besitzt.
#include <print>
int main()
{
std::println("Die Wurzel aus {} ist {{ {} }}", 2, 1.41);
std::println("{1} ist die Wurzel aus {0}\n", 2, 1.41);
}
Die Wurzel aus 2 ist { 1.41 }
1.41 ist die Wurzel aus 2
Sollte der Formatierungsstring nicht in eine Zeile passen, kann er auf mehrere Zeilen verteilt werden.
std::println("Und die Zahl aller "
"Zahlen ist {}",42);
Außer einem Index kann der Platzhalter { } Formatspezifizierer enthalten, welche durch einen Doppelpunkt eingeleitet werden.
:[[fill]align][sign][#][0][width][.precision][type]
Sehen wir uns die Wirkungsweise der einzelnen Formatspezifizierer an.
width
Legt die minimale Stellenanzahl des auszugebenden Datums fest und ist entweder ein positiver Ganzzahlwert oder ein weiterer Platzhalter, um die Stellenanzahl dynamisch festzulegen (siehe Zeile 8).
#include <print>
int main()
{
// Anzahl Stellen ueber Variable definieren
auto anzStellen = 6;
std::println("*{:5}*",10);
std::println("*{:{}}*",10,anzStellen);
}
* 10*
* 10*
[fill]align
align bestimmt die Ausrichtung der Ausgabe und fill definiert das Füllzeichen, das für nicht belegte Stellen verwendet wird. Standardmäßig ist das Füllzeichen ein Leerzeichen.
| align | Ausrichtung |
|---|---|
| < | linksbündig; Standard für nicht-numerische Daten |
| > | rechtsbündig; Standard für numerische Daten |
| ^ | zentriert |
#include <print>
int main()
{
std::println("*{:~<5}*", 10);
std::println("*{:>{}}*", 10, 6);
std::println("{:#^20}", "Text zentriert");
}
*10~~~*
* 10*
###Text zentriert###
sign
Legt fest, wie das Vorzeichen bei numerischen Daten auszugeben ist.
| sign | Vorzeichen |
|---|---|
| - | Vorzeichen nur bei negativen Werten (Standard) |
| + | Vorzeichen bei allen Werten |
| Leerzeichen | Minus-Zeichen bei negativen Werten, Leerzeichen beipositiven Werten |
#include <print>
int main()
{
std::println("*{:<-5}*", -10);
std::println("*{:<+5}*", 10);
std::println("*{:< 5}*", -10);
std::println("*{:< 5}*", 10);
}
*-10 *
*+10 *
*-10 *
* 10 *
#
Gibt bei Integer-Daten ein Präfix für das bei der Ausgabe verwendete Zahlensystem aus (siehe nachfolgenden auch Formatspezifizierer type).
| ausgegebener Präfix | Verwendetes Zahlensystem |
|---|---|
| 0x oder 0X | Ausgabe erfolgte hexadezimal |
| 0b oder 0B | Ausgabe erfolgte binär |
| 0 | Ausgabe erfolgte oktal |
Bei Gleitkommadaten wird immer der Dezimalpunkt mit ausgegeben, unabhängig davon, ob Nachkommastellen vorhanden sind.
#include <print>
int main()
{
std::println("*{:#8B}*", 10);
std::println("*{:#8x}*", 10);
std::println("*{:}*", 12.);
std::println("*{:#}*", 12.);
}
* 0B1010*
* 0xa*
*12*
*12.*
Im Anhang B: Hexadezimal- und Oktalsystem ist eine kleine Einführung in diese Zahlensysteme beschrieben.
0
Füllt nicht belegte führende Stellen mit 0 auf, wenn keine Ausrichtung für die Ausgabe definiert ist.
#include <print>
int main()
{
std::println("*{:#08B}*", 10);
std::println("*{:#08x}*", 10);
std::println("*{:#08}*", 12.);
}
*0B001010*
*0x00000a*
*0000012.*
.precision
Legt bei Gleitkommadaten die Anzahl der Nachkommastellen fest. precision ist entweder ein positiver Integer-Wert oder ein weiterer Platzhalter, um die Anzahl der Nachkommastellen dynamisch festzulegen (siehe Zeile 8).
#include <print>
int main()
{
auto stellen = 5;
std::println("*{}*", 1./3.);
std::println("*{:.3}*", 1./3.);
std::println("*{:.{}}*", 1./3., stellen);
std::println("*{:8.3}*", 1./3.);
std::println("*{:08.3}*", 1./3.);
}
*0.3333333333333333*
*0.333*
*0.33333*
* 0.333*
*0000.333*
Ist das auszugebende Datum ein String, legt precision die Anzahl auszugebenden Zeichen fest.
#include <print>
int main()
{
const char* pText = "Dies ist ein String";
std::println("*{}*", pText);
std::println("*{:.8}*", pText);
}
*Dies ist ein String*
*Dies ist*
type
Bestimmt wie das auszugebende Datum dargestellt wird.
String-Datum:
| type | Darstellung |
|---|---|
| nichts oder s | Ausgabe als String |
Integer-Datum:
| type | Darstellung |
|---|---|
| nichts oder d | Ausgabe als Dezimalzahl |
| b oder B | Ausgabe als Binärzahl; Präfix 0b oder 0B |
| c | Ausgabe als Zeichen |
| o | Ausgabe als Oktalzahl; Präfix 0 |
| x oder X | Ausgabe als Hex-Zahl; Präfix 0x oder 0X |
#include <print>
int main()
{
std::println("233 = {}",233);
std::println("233 = {:#b}",233);
std::println("233 = {:#o}",233);
std::println("233 = {:#x}",233);
}
233 = 233
233 = 0b11101001
233 = 0351
233 = 0xe9
Zeichen-Datum:
| type | Darstellung |
|---|---|
| nichts oder c | Ausgabe als Zeichen |
| b,B,d,o,x,X | Ausgabe als Zahl im entsprechenden Zahlensystem |
#include <print>
int main()
{
std::println("'A' = {}",'A');
std::println("'A' = {:d}",'A');
std::println("'A' = {:x}",'A');
}
'A' = A
'A' = 65
'A' = 41
Gleitkommadatum:
| type | Darstellung |
|---|---|
| nichts | Ausgabe als Festkomma oder mit Exponenten |
| a,A | Ausgabe als Hex-Zahl mit P für den Exponenten |
| e,E | Ausgabe mit Exponenten |
| f,F | Ausgabe als Festkomma |
| g,G | Ausgabe als Festkomma oder mit Exponenten |
#include <print>
int main()
{
std::println("{:#}, {:#}", 1.E3, 1'000'000.);
std::println("{:#a}, {:#A}", 1.E3, 1'000'000.);
std::println("{:#e}, {:#E}", 1.E3, 1'000'000.);
std::println("{:#f}, {:#F}", 1.E3, 1'000'000.);
std::println("{:#g}, {:#G}", 1.E3, 1'000'000.);
}
1000., 1.e+06
1.f4p+9, 1.E848P+19
1.000000e+03, 1.000000E+06
1000.000000, 1000000.000000
1000.00, 1.00000E+06
bool-Datum:
| type | Darstellung |
|---|---|
| nichts oder s | Ausgabe als Text true bzw. false |
| b,B,d,o,x,X | Ausgabe als Integer-Wert |
#include <print>
int main()
{
bool tVal = true;
bool fVal = false;
std::println("{}, {:s}", tVal,fVal);
std::println("{:d}, {:x}", tVal, fVal);
}
true, false
1, 0
char-Zeiger:
Die Ausgabe von Zeigern wird im Kapitel Zeiger behandelt, da noch die Grundlagen hierzu fehlen.
Escape-Sequenzen
Die Ausgabe von nicht-druckbaren Zeichen, wie z.B. ein Zeilenvorschub oder ein Tabulator, erfolgt durch sogenannte Escape-Sequenzen. Sie können an beliebiger Stelle im auszugebenden Text stehen und beginnen mit einem Backslash-Zeichen \, gefolgt von einem Buchstaben, der die auszuführende 'Aktion' beschreibt.
Die nachfolgende Tabelle enthält eine Übersicht über die wichtigsten Escape-Sequenzen.
| Escape-Sequenz | Ausgabe von |
|---|---|
| \a | Alarmton (Beep) |
| \b | Backspace |
| \n | Zeilenvorschub |
| \r | Return (Zeilenanfang) |
| \t | horizontaler Tabulator |
| \\ | Backslash (\) |
| \" | Anführungszeichen |
| \' | Hochkomma |
Die Bedeutung und Wirkungsweise der meisten Escape-Sequenzen dürfte aus deren Beschreibung hervorgehen. Zu beachten ist bei den Escape-Sequenzen \" und \' wann diese notwendig sind. Innerhalb eines Strings ist das Zeichen " als Escape-Sequenz zu definieren, da es standardmäßig diesen begrenzt. Das Zeichen ' benötigt hier keine Escape-Sequenz. Genau andersherum verhält es sich, wenn ein ' als einzelnes Zeichen ausgegeben wird, da ein einzelnes Zeichen in ' eingeschlossen wird.
Es gibt weitere Escape-Sequenzen, die aber seltener eingesetzt werden. Eine vollständige Liste aller Escape-Sequenzen finden Sie unter https://en.cppreference.com unter dem Stichwort Escape sequences.
Der Anhang C: Beispiel zu Escape-Sequenzen enthält ein kleines Beispielprogramm, welches die Wirkungsweise der verschiedenen Escape-Sequenzen demonstriert.
Anhang D: cout Pufferung erläutert kurz die gepufferte Ausgabe von cout.
Der Anhang E: cerr und clog beschreibt zwei weitere Streams für die Ausgabe, die Streams cerr und clog.
Übungen
cout_01
Geben Sie eine vollständige Adresse mit einer Anweisung aus. Der Name, die Straße mit Hausnummer und der Ort mit der Postleitzahl sind jeweils in einer eignen Zeile auszugeben.
Anschließend sind die Zahlen 1 bis 6 als Tabelle mit 2 Zeilen und 3 Spalten auszugeben. Die Spaltenbreits soll 7 Zeichen betragen.
Am Schluss ist ein Alarmton (Beep) auszugeben.
Karl Mueller
Sackgasse 23
12345 Astadt
1 2 3
4 5 6
<Beep>
cout_02
Innerhalb der main() Funktion sind zwei Variablen val und number wie folgt zu definieren:
auto val = 100.0 / 3.0;
auto number = 10;
Geben Sie den Text "100/3 =" und die Variable val als Festkommazahl mit 10 Stellen und 4 Nachkommastellen aus. Nicht belegte Stellen sind mit dem Zeichen '*' auszufüllen.
Anschließend ist die Variable number als Hexadezimal-, Oktal- und Dezimalzahl auszugeben. Bei der Ausgabe ist die Kennung für die aktuelle Zahlenbasis mit auszugeben.
100/3 = ***33.3333
hex:0xa, oct:012, dez:10