iostream für Fortgeschrittene

Willemers Informatik-Ecke

Die Ein- und Ausgabe wurde grundlegend bereits an anderer Stelle behandelt. C++ verwendet das Konzept des Datenstroms, das auch von den modernen Betriebssystemen unterstützt wird.

Eingabe über cin

Zeichenketten

Beim Einlesen von Zeichenketten ist es nicht nur möglich, Objekte vom Typ string einzulesen, es können sogar C-Strings in ein char-Array eingelesen werden. Bei C-Strings ist allerdings Vorsicht geboten, da die Eingabe die Array-Dimension nicht kennt und damit auch nicht berücksichtigt. Eine zu lange Eingabe führt zu einem Pufferüberlauf, also einem Schreiben in fremde Speicherbereiche.

[Einlesen von Zeichenketten]

#include <iostream>
#include <string>
using namespace std;

int main()
{
    char a[5], b[20]; // oder: string a, b;
    cin >> a >> b;
    cout << a << "," << b << endl;
}

Das Eingabeobjekt kann wie eine boolesche Variable abgefragt werden. Dann liefert es false, wenn EOF erreicht ist. Dieser Vorgang ist analog zu der Prüfung auf Erreichen des Dateiendes (EOF - End Of File).

[Boolescher Charakter]

while (cin >> Zahl)
{

}

Äquivalent zur direkten Abfrage des Eingabe-Objekts ist der Aufruf der Elementfunktion cin.eof(). Das EOF wird auf der Tastatur durch ctrl-D unter UNIX und ctrl-Z unter MS-DOS oder MS-Windows erzeugt. Da diese Art der Programmsteuerung einem normalen Anwender nicht leicht zu vermitteln ist, eignet sich dieses Verfahren eigentlich nur, wenn Dateien in die Standardeingabe umgelenkt werden.

Einlesen einer Zeile

Beim Einlesen von Daten über cin wird normalerweise der so genannte >>Whitespace<<, also alle Leerzeichen, Tabulatoren und Zeilenvorschübe, als Trennzeichen entfernt. Das kann lästig sein, wenn Zeichenketten eingelesen werden sollen, die auch Leerzeichen enthalten können.

getline() global

Zum Einlesen einer kompletten Eingabezeile gibt es die globale Funktion getline(). Sie erwartet als ersten Parameter ein Stream-Objekt. Der zweite Parameter ist vom Typ string. Das hat den Vorteil, dass kein Pufferüberlauf überwacht werden muss. Optional kann in einem dritten Parameter angegeben werden, welches das Abschlusszeichen sein soll. Vorgegeben ist das Zeilenendezeichen.

int main()
{
    string BruchString;
    getline(cin, BruchString)
    cout << BruchString << endl;
}

Elementfunktion

Die Stream-Klassen haben eine Elementfunktion getline(). Deren erster Parameter ist kein string, sondern ein klassischer C-String, also ein Zeiger auf char. Entsprechend ist der zweite Parameter die Größe des zur Verfügung stehenden Puffers. Auch hier ist es optional möglich, ein Begrenzungszeichen anzugeben.

int main()
{
    char BruchString[MAXSTR];
    cin.getline(BruchString, sizeof(BruchString))
    cout << BruchString << endl;
}
Die Funktion getline() liefert in allen Varianten immer eine Referenz auf den Eingabestrom zurück.

Manipulatoren

Manipulatoren dienen dazu, die Ausgabe aufzubereiten und zu formatieren. Es wurden bereits ein paar einfache Manipulatoren vorgestellt. Manipulatoren können bei Ausgabeströmen zwischen die Umleitungsoperatoren eingefügt werden. Um die Manipulatoren verwenden zu können, müssen Sie zunächst die Datei iomanip einbinden.

Zeilenende endl

Der Manipulator endl erzeugt einen Zeilenvorschub und sorgt dafür, dass die bisher ausgegebene Zeile sofort auf die Ausgabeeinheit geschrieben wird. Damit werden eventuell vorhandene Zwischenpuffer des Betriebssystems geleert.

Ausgabebreite setw

Dem Manipulator setw() wird als Parameter die Breite angegeben, die für das nächste Ausgabeobjekt mindestens zur Verfügung gestellt werden soll. Falls der Platz größer ist als benötigt, wird die Ausgabe rechtsbündig ausgerichtet. Der verbleibende Platz wird mit Leerzeichen aufgefüllt. Das Leerzeichen kann mit dem Manipulator setfill() verändert werden. Als Parameter erwartet er ein Zeichen. Der Manipulator bleibt solange wirksam, bis das nächste Mal setfill() aufgerufen wird. Die Bündigkeit kann mit den Manipulatoren left oder right umgestellt werden:

    cout << setw(8) << i << endl;
    cout << setfill('-');
    cout << setw(8) << i << endl;
    cout << left << setw(8) << i << endl;

Die Ausgabe des Programms sieht so aus, wenn die Variable i den Inhalt 725 hat:

     725
-----725
725-----

Zahlenbasis

Durch einen Manipulator kann eingestellt werden, zu welcher Zahlenbasis alle folgenden Ausgaben erscheinen sollen. Dabei gibt es dec für dezimale Zahlen, oct für die oktale Darstellung und schließlich hex für hexadezimale Zahlen. Es werden nur die reinen Zahlen angezeigt. Die für C und C++ so typischen Konstantenkennungen wie 0x für hexadezimal und einer führenden 0 für oktal werden nicht dargestellt. Ein solches Verhalten kann aber eingeschaltet werden, indem der Manipulator showbase aufgerufen wird. Mit noshowbase wird es wieder abgeschaltet.

    cout << oct << endl;
    cout << setw(8) << i << endl;
    cout << setfill('-');
    cout << setw(8) << i << endl;
    cout << hex << left << setw(8) << i << endl;

Die Ausgabe des Programms sieht so aus, wenn die Variable i den Inhalt 725 hat:

    1325
----1325
2d5-----

true oder 1

Für die Konstante true wird normalerweise 1 und für false 0 ausgegeben. Sie können dies bei einigen Compilern [1] durch den Manipulator boolalpha so umstellen, dass >>true<< und >>false<< in der Ausgabe erscheinen. Mit noboolalpha erscheinen wieder 1 und 0. [Manipulatoren]
Manipulator Wirkung
endl Fügt Zeilenende ein
setw(n) Spalte für nächstes Ausgabeobjekt ist n Stellen breit
left linksbündig ausrichten
right rechtsbündig ausrichten
setfill(c) c als Füllzeichen verwenden
dec Stellt Zahlen dezimal dar
oct Stellt Zahlen oktal dar
hex Stellt Zahlen hexadezimal dar
showbase Zeigt 0x bei hexadezimaler und 0 bei oktaler Darstellung
boolalpha Stellt true und false textuell dar
noboolalpha Stellt true als 1 und false als 0 dar

Fließkommazahlen

Für Fließkommazahlen gibt es natürlich auch Manipulatoren. Zunächst funktioniert auch hier setw() zur Festlegung der Ausgabebreite. Die Darstellungsart kann auf scientific umgestellt werden. Dann werden die Zahlen in Exponentialschreibweise mit einer Stelle vor dem Dezimalpunkt dargestellt. Mit dem Manipulator fixed wird zur Festkommadarstellung umgeschaltet. Der Manipulator setprecision() ist für die Genauigkeit zuständig. Als Parameter wird ihm übergeben, wie viele Stellen der Zahl angezeigt werden sollen. Auch die Manipulatoren scientific und fixed sind noch nicht bei allen C++-Compilern implementiert. [Fließkommamanipulatoren]
Manipulator Wirkung
showpoint Darstellung mit Dezimalpunkt und Nachkommastellen
noshowpoint Nur die relevanten Stellen werden ausgegeben
scientific Fließkommazahl in wissenschaftlicher Darstellung
fixed Festgelegte Nachkommastellen
setprecision(n) Genauigkeit; n ist die Anzahl der Stellen
Anstatt Manipulatoren in den Ausgabestrom zu legen, können auch Elementfunktionen des Stream-Objekts aufgerufen werden. Allerdings heißen die Elementfunktionen geringfügig anders. Dabei ergeben sich folgende Unterschiede:cl ({vgl. Davis, Stephen R.: C++ für Dummies, MITP, Bonn, 1999, S. 302.) [Manipulatoren und Elementfunktionen]
Manipulator Elementfunktion
setw(n) width(n)
setfill(c) fill(c)
setprecision(n) precision(n)
Besonders interessant ist die Elementfunktion setf(). Mit dieser Funktion lassen sich auch die Manipulatoren funktional nachbilden, die beispielsweise im GNU C++-Compiler 2.95.3 nicht vorhanden sind.

cout.setf(ios::left); // entspricht: cout << left;

Ein Manipulator hat gegenüber den Elementfunktionen den Vorteil, dass er einfach in den Ausgabestrom hineingelegt werden kann. Ein Manipulator wird vom Umleitungsoperator daran erkannt, dass er einem der folgenden Prototypen entspricht: (vgl. Jakobs, Holger: Einführung in ISO C++, PDF-Datei v. 12.4.2000, S. 75)

[Prototypen für Manipulatoren]

ios     & function(ios &);
istream & function(istream &); 
ostream & function(ostream &);
Wenn Sie eine Funktion schreiben, die solche Parameter und Rückgabewerte hat, erstellen Sie damit einen Manipulator. Der Name des Manipulators ist der Name der Funktion. Wenn Sie also den left-Manipulator unter GNU C++ nachbilden wollen, erstellen Sie die folgende Funktion namens left().

[Selbst geschriebener left-Manipulator]

ios& left(ios& i)
{
    i.setf(ios::left);
    return i;
}

Unfertig

Das Thema Manipulatoren ist sicher noch nicht abgeschlossen. Man merkt es daran, dass nicht alle im Standard definierten Manipulatoren in den Compilern umgesetzt sind. So wird in den Programmen sicher noch einige Zeit die Funktion printf() verwendet werden, um beispielsweise eine Fließkommazahl mit zwei Nachkommastellen auszugeben:

[Nachkomma-Darstellung]

printf("%12.2f\n", Kapital);

Für die Variable Kapital wird im Ausgabestrom 12 Stellen Platz für Vorzeichen, die Vor- und Nachkommastellen und den Dezimalpunkt freigehalten. Wenn weniger Stellen benötigt werden, wird der Wert rechtsbündig dargestellt. Dabei zeigt die Ausgabe immer zwei Nachkommastellen an.


[1]
Es funktioniert bei Borland C++, ging aber unter GNU C++ schief.


Informatik-Ecke Einstieg in C++ (C) Copyright 2005 Arnold Willemer