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.