vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Woche 1

Tag 6

Grundlagen der Ein- und Ausgabe

In den meisten Ihrer Programme werden Sie Informationen auf dem Bildschirm ausgeben oder Informationen von der Tastatur einlesen müssen. In einem Großteil der bisher vorgestellten Beispielprogramme wurde damit schon gearbeitet, auch wenn Sie vielleicht nicht verstanden haben, wie alles zusammenhängt. Heute lernen Sie:

Die heutige Lektion soll diese Themen nicht vollständig abhandeln, sondern lediglich die grundlegenden Informationen vermitteln, so dass Sie mit dem Schreiben richtiger Programme beginnen können. Etwas weiter hinten in diesem Buch werden wir auf diese Themen noch ausführlicher eingehen.

Informationen auf dem Bildschirm anzeigen

In den meisten Ihrer Programme werden Sie sicherlich eine Ausgabe auf dem Bildschirm vorsehen. Und das geschieht am häufigsten über die zwei Bibliotheksfunktionen von C, printf() und puts().

Die Funktion printf()

Die Funktion printf() ist Teil der C-Standardbibliothek. Sie stellt wahrscheinlich die flexibelste Option zur Ausgabe von Daten auf den Bildschirm dar. printf() ist Ihnen bereits in vielen Beispielen in diesem Buch begegnet. Jetzt sollen Sie erfahren, wie die Funktion arbeitet.

Die Ausgabe einer Textmeldung auf den Bildschirm ist einfach. Rufen Sie die Funktion printf() auf und übergeben Sie ihr die entsprechende Nachricht in doppelten Anführungszeichen. Um zum Beispiel »Ein Fehler ist aufgetreten!« auf den Bildschirm auszugeben, schreiben Sie

printf("Ein Fehler ist aufgetreten!");

Doch meist müssen Sie nicht nur eine Textmeldung, sondern auch den Wert von Programmvariablen ausgeben. Dies ist etwas komplizierter, als nur eine Meldung auszugeben. Angenommen Sie wollen zum Beispiel den Wert der numerischen Variablen x auf dem Bildschirm zusammen mit erläuterndem Text ausgeben und dieser Text soll in einer neuen Zeile beginnen. Dazu könnten Sie die printf()- Funktion wie folgt verwenden:

printf("\nDer Wert von x ist %d", x);

Unter der Voraussetzung, dass der Wert von x 12 ist, wäre die Ausgabe auf dem Bildschirm dann:

Der Wert von x ist 12

In diesem Beispiel werden printf() zwei Argumente übergeben. Das erste Argument steht in doppelten Anführungszeichen und wird Formatstring genannt. Das zweite Argument ist der Name der Variablen (x), die den auszugebenden Wert enthält.

printf()-Formatstrings

Ein printf()-Formatstring spezifiziert, wie die Ausgabe zu formatieren ist. Sehen Sie im Folgenden die drei möglichen Komponenten eines Formatstrings:

Sequenz

Bedeutung

\a

Beep (Akustisches Signal)

\b

Backspace

\n

Neue Zeile

\t

Horizontaler Tabulator

\\

Backslash

\?

Fragezeichen

\'

Einfache Anführungszeichen

Tabelle 6.1: Die gebräuchlichsten Escape-Sequenzen.

Die Escape-Sequenzen von printf()

Escape-Sequenzen dienen dazu, die Position der Ausgabe durch Verschieben des Cursors auf dem Bildschirm zu steuern. Sie werden aber auch dazu genutzt, um Zeichen auszugeben, die ansonsten für printf()eine besondere Bedeutung haben. Um zum Beispiel einen einfachen Backslash auszugeben, müssen Sie einen doppelten Backslash (\\) in den Formatstring einbauen. Der erste Backslash teilt printf() mit, dass der zweite Backslash als literales Zeichen zu verstehen ist und nicht als Beginn einer Escape-Sequenz. Im Allgemeinen teilen Sie printf() mit dem Backslash mit, dass das nächste Zeichen in besonderer Weise zu interpretieren ist. Sehen Sie im Folgenden einige Beispiele:

Sequenz

Bedeutung

n

Das Zeichen n

\n

Neue Zeile

\"

Das doppelte Anführungszeichen

"

Anfang oder Ende eines Strings

Listing 6.1 verwendet einige der gängigsten Escape-Sequenzen.

Listing 6.1: Escape-Sequenzen zusammen mit printf().

1:   /* Beispiele für die gängigsten Escape-Sequenzen */
2:
3: #include <stdio.h>
4:
5: #define VERLASSEN 3
6:
7: int menue_option_einlesen( void );
8: void bericht_anzeigen ( void );
9:
10: int main(void)
11: {
12: int option = 0;
13:
14: while (option != VERLASSEN)
15: {
16: option = menue_option_einlesen();
17:
18: if (option == 1)
19: printf("\nAkustisches Signal des Computers\a\a\a" );
20: else
21: {
22: if (option == 2)
23: bericht_anzeigen();
24: }
25: }
26: printf("Sie haben die Option Verlassen gewählt!\n");
27:
28: return 0;
29: }
30:
31: int menue_option_einlesen( void )
32: {
33: int auswahl = 0;
34:
35: do
36: {
37: printf( "\n" );
38: printf( "\n1 - Akustisches Signal des Computers" );
39: printf( "\n2 - Bericht anzeigen");
40: printf( "\n3 - Verlassen");
41: printf( "\n" );
42: printf( "\nGeben Sie Ihre Wahl ein:" );
43:
44: scanf( "%d", &auswahl );
45:
46: }while ( auswahl < 1 || auswahl > 3 );
47:
48: return auswahl;
49: }
50:
51: void bericht_anzeigen( void )
52: {
53: printf( "\nMUSTERBERICHT                    " );
54: printf( "\n\n Sequenz\tBedeutung" );
55: printf( "\n=========\t=======" );
56: printf( "\n\\a\t\tBeep (Akustisches Signal)" );
57: printf( "\n\\b\t\tBackspace" );
58: printf( "\n...\t\t...");
59: }

1 - Akustisches Signal des Computers
2 - Bericht anzeigen
3 - Verlassen

Geben Sie Ihre Wahl ein:1

Akustisches Signal des Computers

1 - Akustisches Signal des Computers
2 - Bericht anzeigen
3 - Verlassen

Geben Sie Ihre Wahl ein:2

MUSTERBERICHT
Sequenz Bedeutung
========= =======
\a Beep (Akustisches Signal)
\b Backspace
... ...
1 - Akustisches Signal des Computers
2 - Bericht anzeigen
3 - Verlassen

Geben Sie Ihre Wahl ein:3
Sie haben die Option Verlassen gewählt!

Listing 6.1 scheint im Vergleich zu den bisherigen Beispielen ziemlich lang und es enthält einige Zusätze, die man genauer untersuchen sollte. Die Header-Datei stdio.h wird in Zeile 3 eingebunden, da in diesem Listing printf() verwendet wird. Zeile 5 definiert eine Konstante namens VERLASSEN. Vom Abschnitt »Daten speichern: Variablen und Konstanten« aus Tag 2 wissen Sie vielleicht noch, dass Sie mit #define die Konstante VERLASSEN gleichsetzen mit dem Wert 3. Die Zeilen 7 und 8 enthalten Funktionsprototypen. Dieses Programm verwendet zwei Funktionen: menue_option_einlesen() und bericht_anzeigen(). Die Funktion menue_option_einlesen() wird in den Zeilen 31 bis 49 definiert. Sie hat Ähnlichkeit mit der Menü-Funktion aus Listing 5.5. Die Zeilen 37 und 41 enthalten Aufrufe von printf(), in denen die Escape-Sequenz Neue Zeile ausgegeben wird. Die Zeilen 38, 39, 40 und 42 enthalten neben dem Neue-Zeile-Escape-Zeichen noch Text zum Ausgeben. Zeile 37 könnte man fortlassen, wenn man Zeile 38 wie folgt ändern würde:

printf( "\n\n1 - Akustisches Signal des Computers" );

Mit der zusätzlichen Zeile 37 ist das Programm jedoch leichter zu lesen.

Werfen wir einen Blick auf die Funktion main(). In Zeile 14 beginnt eine while- Schleife, deren Anweisungen so lange durchlaufen werden, wie option ungleich VERLASSEN ist. Da VERLASSEN eine Konstante ist, hätten Sie sie auch durch 3 ersetzen können. Dann wäre das Programm jedoch nicht so klar. Zeile 16 weist den Code der vom Anwender getroffenen Auswahl der Variablen option zu, die dann in den Zeilen 18 bis 25 in einer if-Anweisung analysiert wird. Wenn der Anwender 1 wählt, gibt Zeile 19 das Neue-Zeile-Zeichen, eine Meldung und drei Warntöne aus. Und wenn der Anwender 2 wählt, ruft Zeile 23 die Funktion bericht_anzeigen() auf.

Die Funktion bericht_anzeigen() ist in den Zeilen 51 bis 59 definiert. Diese einfache Funktion zeigt, wie einfach es ist, mit printf() und den Escape-Sequenzen formatierte Informationen auf dem Bildschirm auszugeben. Das Neue-Zeile-Zeichen haben Sie bereits kennen gelernt. In den Zeilen 54 bis 58 finden Sie darüber hinaus das Escape-Zeichen für den Tabulator: \t. Das Tabulatorzeichen richtet die Spalten des Berichts vertikal aus. Die Zeilen 56 und 57 mögen auf den ersten Blick etwas verwirren, doch wenn Sie sie von links nach rechts durchgehen, dürften sie den Sinn schnell erkennen. Zeile 56 gibt eine neue Zeile aus (\n), danach einen Backslash (\) gefolgt von dem Buchstaben a und anschließend zwei Tabulatoren (\t\t). Die Zeile endet mit einem beschreibenden Text (Beep (Akustisches Signal)). Zeile 57 folgt dem gleichen Muster.

Dieses Programm gibt die ersten zwei Zeilen der Tabelle 6.1 zusammen mit einem Titel für den Bericht und Spaltenüberschriften aus. In Übung 9 am Ende dieser Lektion sollen Sie dieses Programm vervollständigen, so dass es den Rest der Tabelle ausgibt.

Die printf()-Konvertierungsspezifizierer

Der Formatstring muss für jede ausgegebene Variable einen Konvertierungsspezifizierer enthalten. Die Funktion printf() gibt jede Variable so aus, wie es durch den entsprechenden Konvertierungsspezifizierer vorgegeben ist. Mehr dazu erfahren Sie am Tag 15, »Mit Dateien arbeiten«. Im Moment reicht es, wenn Sie sich vergewissern, dass Sie stets den Konvertierungsspezifizierer verwenden, der mit dem Typ der auszugebenden Variablen übereinstimmt.

Was genau ist damit gemeint? Wenn Sie eine vorzeichenbehaftete Dezimalzahl (Typ int oder long) ausgeben wollen, verwenden Sie den Konvertierungsspezifizierer %d. Für vorzeichenlose Dezimalzahlen (Typ unsigned int oder unsigned long) verwendet man %u und für Fließkomma-Variablen (Typ float oder double) den Spezifizierer %f. Die am häufigsten verwendeten Konvertierungsspezifizierer sind in Tabelle 6.2 zusammengefasst

Spezifizierer

Bedeutung

konvertierte Typen

%c

Einfaches Zeichen

char

%d

Vorzeichenbehaftete Dezimalzahl

int, short

%ld

Große vorzeichenbehaftete Dezimalzahl

long

%f

Fließkommazahl

float, double

%s

Zeichenstring

char arrays

%u

Vorzeichenlose Dezimalzahl

unsigned int, unsigned short

%lu

Große vorzeichenlose Dezimalzahl

unsigned long

Tabelle 6.2: Die gebräuchlichsten Konvertierungsspezifizierer.

Alle Programme, die printf() verwenden,
sollten die Header-Datei stdio.h einbinden.

Der literale Text eines Formatspezifizierers ist alles, was weder Escape-Sequenz noch Konvertierungsspezifizierer ist. Literaler Text wird genauso ausgegeben, wie er da steht, einschließlich aller Leerzeichen.

Kann man auch Werte von mehreren Variablen ausgeben? Eine einzige printf()- Anweisung kann eine unbegrenzte Anzahl von Variablen ausgeben, aber der Formatstring muss für jede Variable einen Konvertierungsspezifizierer enthalten. Die Konvertierungsspezifizierer sind mit den Variablen paarweise verbunden und werden von links nach rechts gelesen. Wenn Sie also schreiben

printf("Rate = %f, Betrag = %d", rate, betrag);

bildet die Variable rate ein Paar mit dem Spezifizierer %f und die Variable betrag mit dem Spezifizierer %d. Die Positionen der Konvertierungsspezifizierers im Formatstring legen die Position der Ausgabe fest. Wenn printf() mehr Variablen übergeben werden, als es Konvertierungsspezifizierer gibt, werden die überflüssigen Variablen nicht ausgegeben. Gibt es hingegen mehr Spezifizierer als Variablen, geben die unbenutzten Spezifizierer »Müll« aus.

Sie können mit printf() nicht nur die Werte von Variablen ausgeben. Jeder gültige C-Ausdruck kann als Argument dienen. Um zum Beispiel die Summe von x und y auszugeben, könnten Sie schreiben

z = x + y;
printf("%d", z);

Sie könnten aber auch schreiben

printf("%d", x + y);

Listing 6.2 veranschaulicht Ihnen die Verwendung von printf(). Am Tag 15 erhalten Sie ausführlichere Informationen zu dieser Funktion.

Listing 6.2: Mit printf() numerische Werte ausgeben.

1:   /* Beispiel, das mit printf() numerische Werte ausgibt. */
2:
3: #include <stdio.h>
4:
5: int a = 2, b = 10, c = 50;
6: float f = 1.05, g = 25.5, h = -0.1;
7:
8: int main(void)
9: {
10: printf("\nDezimalwerte ohne Tabulatoren: %d %d %d", a, b, c);
11: printf("\nDezimalwerte mit Tabulatoren: \t%d \t%d \t%d", a, b, c);
12:
13: printf("\nDrei Fliesskommazahlen in einer Zeile: \t%f\t%f\t%f",f,g,h);
14: printf("\nDrei Fliesskommazahlen in drei Zeilen: \n\t%f\n\t%f\n\t%f",
15: f,g,h);
16: printf("\nDie Quote beträgt %f%%", f);
17: printf("\nDas Ergebnis von %f/%f = %f\n", g, f, g / f);
18:
19: return 0;
20: }

Dezimalwerte ohne Tabulatoren: 2 10 50
Dezimalwerte mit Tabulatoren: 2 10 50
Drei Fliesskommazahlen in einer Zeile: 1.050000 25.500000 -0.100000
Drei Fliesskommazahlen in drei Zeilen:
1.050000
25.500000
-0.100000
Die Quote beträgt 1.050000%
Das Ergebnis von 25.500000/1.050000 = 24.285715

Listing 6.2 gibt neun Zeilen aus. Die Zeilen 10 und 11 geben jeweils drei Dezimalzahlen aus: a, b und c. In Zeile 10 stehen diese Zahlen ohne Tabulator einfach hintereinander, in Zeile 11 sind sie durch Tabulatoren getrennt. Die Zeile 13 und 14 geben jeweils drei Variablen vom Typ float aus: f, g und h. In Zeile 13 werden sie in einer Zeile und in Zeile 14 in drei Zeilen ausgegeben. Zeile 16 gibt eine Fließkommazahl, f, gefolgt von einem Prozentzeichen aus. Da ein Prozentzeichen in der Regel darauf hinweist, dass eine Variable auszugeben ist, müssen Sie zwei Prozentzeichen hintereinander setzen, um ein einfaches Prozentzeichen anzuzeigen. Dies entspricht der Vorgehensweise wie beim Backslash-Escape-Zeichen. Zeile 17 schließlich veranschaulicht die Ausgabe von Ausdrücken - wie zum Beispiel g/f.

Was Sie tun sollten

Versuchen Sie nicht, mehrere Textzeilen in einer printf()-Anweisung unterzubringen. Meistens ist es übersichtlicher, wenn Sie mehrere Zeilen auf mehrere printf()- Anweisungen verteilen, statt nur eine printf()-Anweisung zu verwenden und diese mit Neue-Zeile-Zeichen (\n) zu spicken.

Vergessen Sie das Neue-Zeile-Zeichen nicht, wenn Sie mehrere Zeilen mit Informationen in mehreren printf()-Anweisungen ausgeben wollen.

Achten Sie auf die Schreibweise von stdio.h. Viele C-Programmierer vertippen sich häufig und schreiben studio.h. Die Header-Datei schreibt sich aber ohne u.

Die Funktion printf()

#include <stdio.h>
printf( Formatstring[,Argumente,...]);

printf() ist eine Funktion, die einen Formatstring mit Konvertierungsspezifizierern und für jeden Konvertierungsspezifizierer ein zugehöriges Argument übernimmt. Die Funktion gibt die formatierten Informationen auf dem Standardausgabegerät, normalerweise dem Bildschirm, aus. Bei Verwendung von printf() müssen Sie die Header-Datei für die Standardein-/-ausgabe, stdio.h, einbinden.

Der Formatstring ist obligatorisch, die Argumente hingegen sind optional. Zu jedem Argument muss es einen Konvertierungsspezifizierer geben. Die gebräuchlichsten Konvertierungsspezifizierer finden Sie in Tabelle 6.2.

Der Formatstring kann außerdem Escape-Sequenzen enthalten. In Tabelle 6.1 sind die am häufigsten verwendeten Escape-Sequenzen aufgeführt.

Sehen Sie im Folgenden einige Beispiele für printf()-Aufrufe und die dazugehörige Ausgabe:

Beispiel 1: Eingabe

#include <stdio.h>
int main(void)
{
printf("Dies ist ein Beispiel für eine Ausgabe!\n");
return 0;
}

Beispiel 1: Ausgabe

Dies ist ein Beispiel für eine Ausgabe!

Beispiel 2: Eingabe

printf ("Dieser Befehl gibt ein Zeichen, %c\neine Zahl, 
%d\nund eine Fließkommazahl, %f\naus ", 'z', 123, 456.789);

Beispiel 2: Ausgabe

Dieser Befehl gibt ein Zeichen, z
eine Zahl, 123
und eine Fließkommazahl, 456.789
aus

Nachrichten mit puts() ausgeben

Um Text auf dem Bildschirm anzuzeigen, kann auch die Funktion puts() verwendet werden. Sie erlaubt allerdings nicht die Ausgabe numerischer Variablen. Die Funktion puts() übernimmt einen einfachen String als Argument und gibt diesen aus, wobei am Ende automatisch eine neue Zeile begonnen wird. Die Anweisung

puts("Hallo, Welt.");

hat daher den gleichen Effekt wie

printf("Hallo, Welt.\n");

Sie können in dem String, der puts() übergeben wird, auch Escape-Sequenzen (einschließlich \n) verwenden. Sie bewirken das Gleiche wie bei der Funktion printf() (Tabelle 6.1 listet die gebräuchlichsten Escape-Sequenzen auf).

Wie bei printf() muss in jedem Programm, das puts() verwendet, die Header-Datei stdio.h mit angegeben werden (falls nicht schon geschehen).

Was Sie tun sollten

Was nicht

Verwenden Sie immer dann, wenn Sie Text ohne zusätzliche Variablen ausgeben wollen, die Funktion puts() anstelle von printf().

Versuchen Sie nicht, Konvertierungsspezifizierer mit der puts()-Anweisung zu verwenden.

Die Funktion puts()

#include <stdio.h>
puts( string );

puts() ist eine Funktion, die einen String auf dem Standardausgabegerät, normalerweise dem Bildschirm, ausgibt. Wenn Sie puts() verwenden, müssen Sie die Header-Datei stdio.h für die Standarein-/-ausgabe einbinden. puts() hängt automatisch ein Neues-Zeile-Zeichen an das Ende des auszugebenden Strings an. Der Formatstring darf Escape-Sequenzen enthalten. Die gängigsten Escape-Sequenzen finden Sie in Tabelle 6.1.

Sehen Sie im Folgenden einige Beispiele für puts()-Aufrufe und die dazugehörige Ausgabe:

Beispiel 1: Eingabe

puts("Dieser Text wird mit der puts()-Funktion ausgegeben!");

Beispiel 1: Ausgabe

Dieser Text wird mit der puts()-Funktion ausgegeben!

Beispiel 2: Eingabe

puts("Diese Ausgabe steht in der ersten Zeile.\nDiese in der zweiten.");
puts("Diese Ausgabe erfolgt in der dritten Zeile.");
puts("Mit printf() würden die vier Zeilen in zwei Zeilen stehen!");

Beispiel 2: Ausgabe

Diese Ausgabe steht in der ersten Zeile.
Diese in der zweiten.
Diese Ausgabe erfolgt in der dritten Zeile.
Mit printf() würden die vier Zeilen in zwei Zeilen stehen!

Numerische Daten mit scanf() einlesen

Ebenso häufig, wie Programme Daten auf dem Bildschirm ausgeben müssen, sind sie gezwungen, Daten von der Tastatur einzulesen. Am flexibelsten ist dabei die Bibliotheksfunktion scanf().

Die Funktion scanf() liest Daten, die einem vorgegebenen Format entsprechen, von der Tastatur ein und weist diese einer oder mehreren Programmvariablen zu. Wie schon printf() verwendet auch scanf() einen Formatstring, um das Format der Eingabe festzulegen. Dabei kommen im Formatstring die gleichen Konvertierungsspezifizierer wie bei printf() zur Anwendung. So liest zum Beispiel die Anweisung

scanf("%d", &x);

eine Dezimalzahl von der Tastatur ein und weist sie der Integer-Variablen x zu. Entsprechend liest die folgende Anweisung eine Fließkommazahl von der Tastatur ein und weist sie dann der Variablen rate zu:

scanf("%f", &rate);

Was jedoch hat das kaufmännische Und (&) vor dem Variablennamen zu suchen? Das &-Symbol ist der Adressoperator von C, der am Tag 8, »Zeiger«, noch ausführlich beschrieben wird. Momentan reicht es, sich zu merken, dass in der Argumentenliste von scanf() vor jedem numerischen Variablennamen das Symbol & gesetzt werden muss (es sei denn die Variable ist ein Zeiger, was ebenfalls erst am Tag 8 erläutert wird).

Mit einer einzigen scanf()-Funktion können Sie mehrere Werte einlesen. Voraussetzung ist jedoch, dass Sie mehrere Konvertierungsspezifizierer im Formatstring und mehrere Variablennamen (jeweils mit vorangestelltem &-Zeichen) in der Argumentenliste angeben. Die folgende Anweisung nimmt einen Integer- und einen Fließkommawert auf und weist sie den Variablen x beziehungsweise rate zu:

scanf("%d %f", &x, &rate);

Wenn mehrere Variablen eingegeben werden, verwendet scanf() Whitespace- Zeichen, um die Eingabe in Felder zu unterteilen. Zu den Whitespace-Zeichen gehören Leerzeichen, Tabulatoren oder Neue-Zeilen-Zeichen. Jeder Konvertierungsspezifizierer in dem scanf()-Formatstring wird mit einem Eingabefeld abgeglichen. Das Ende eines Eingabefeldes wird durch ein Whitespace-Zeichen markiert.

Dadurch sind Sie ziemlich flexibel. Eine Eingabe für den obigen scanf()-Aufruf könnte beispielsweise wie folgt aussehen:

10 12.45

Oder Sie könnten die Werte so eingeben:

10                   12.45

Oder so:

10
12.45

Solange ein Whitespace-Zeichen zwischen den Werten steht, kann scanf() jeden Wert seiner Variablen zuweisen.

Wie schon bei den anderen heute vorgestellten Funktionen müssen Programme, die scanf() verwenden, die Header-Datei stdio.h einbinden. Listing 6.3 zeigt ein Beispiel für den Einsatz von scanf() (siehe dazu auch das Kapitel zu Tag 15).

Listing 6.3: Numerische Werte mit scanf() einlesen.

1:   /* Beispiel für die Verwendung von scanf() */
2:
3: #include <stdio.h>
4:
5: #define VERLASSEN 4
6:
7: int menue_option_einlesen( void );
8:
9: int main(void)
10: {
11: int option = 0;
12: int int_var = 0;
13: float float_var = 0.0;
14: unsigned unsigned_var = 0;
15:
16: while (option != VERLASSEN)
17: {
18: option = menue_option_einlesen();
19:
20: if (option == 1)
21: {
22: puts("\nGeben Sie eine vorzeichenbehaftete Dezimalzahl ein \
(z.B. -123)");
23: scanf("%d", &int_var);
24: }
25: if (option == 2)
26: {
27: puts("\nGeben Sie eine Fliesskommazahl ein (z.B. 1.23)");
28:
29: scanf("%f", &float_var);
30: }
31: if (option == 3)
32: {
33: puts("\nGeben Sie eine vorzeichenlose Dezimalzahl ein \
34: (z.B. 123)" );
35: scanf( "%u", &unsigned_var );
36: }
37: }
38: printf("\nIhre Werte lauten: int: %d float: %f unsigned: %u \n",
39: int_var, float_var, unsigned_var );
40:
41: return 0;
42: }
43:
44: int menue_option_einlesen( void )
45: {
46: int auswahl = 0;
47:
48: do
49: {
50: puts( "\n1 - Eine vorzeichenbehaftete Dezimalzahl einlesen" );
51: puts( "2 - Eine Fliesskommazahl einlesen" );
52: puts( "3 - Eine vorzeichenlose Dezimalzahl einlesen" );
53: puts( "4 - Verlassen" );
54: puts( "\nTreffen Sie eine Wahl:" );
55:
56: scanf( "%d", &auswahl );
57:
58: }while ( auswahl < 1 || auswahl > 4 );
59:
60: return auswahl;
61: }

1 - Eine vorzeichenbehaftete Dezimalzahl einlesen
2 - Eine Fliesskommazahl einlesen
3 - Eine vorzeichenlose Dezimalzahl einlesen
4 - Verlassen

Treffen Sie eine Wahl:
1

Geben Sie eine vorzeichenbehaftete Dezimalzahl ein (z.B. -123)
-123

1 - Eine vorzeichenbehaftete Dezimalzahl einlesen
2 - Eine Fliesskommazahl einlesen
3 - Eine vorzeichenlose Dezimalzahl einlesen
4 - Verlassen

Treffen Sie eine Wahl:
3

Geben Sie eine vorzeichenlose Dezimalzahl ein (z.B. 123)
321

1 - Eine vorzeichenbehaftete Dezimalzahl einlesen
2 - Eine Fliesskommazahl einlesen
3 - Eine vorzeichenlose Dezimalzahl einlesen
4 - Verlassen

Treffen Sie eine Wahl:
2

Geben Sie eine Fliesskommazahl ein (z.B. 1.23)
1231.123

1 - Eine vorzeichenbehaftete Dezimalzahl einlesen
2 - Eine Fliesskommazahl einlesen
3 - Eine vorzeichenlose Dezimalzahl einlesen
4 - Verlassen

Treffen Sie eine Wahl:
4

Ihre Werte lauten: int: -123 float: 1231.123047 unsigned: 321

Listing 6.3 verwendet das gleiche Menükonzept wie Listing 6.1. Die Unterschiede in menue_option_einlesen() (Zeilen 44 bis 61) sind zwar geringfügiger Art, sollten aber dennoch nicht unberücksichtigt bleiben. Zum einen wird anstelle von printf() die Funktion puts() verwendet. Da keine Variablen ausgegeben werden, besteht keine Notwendigkeit für printf(). Durch das Einsetzen von puts() wiederum wurden in den Zeilen 51 bis 53 die Neue-Zeile-Zeichen entfernt. Zeile 58 hat ebenfalls eine Änderung erfahren und erlaubt die Eingabe von Werten zwischen 1 und 4, da jetzt unter vier Menüoptionen gewählt werden kann. Beachten Sie, dass Zeile 56 nicht geändert wurde, jetzt aber vielleicht etwas mehr Sinn ergibt. scanf() liest einen Dezimalwert ein und legt ihn in der Variablen auswahl ab. Die Funktion liefert in Zeile 60 den Wert von auswahl zurück an das aufrufende Programm.

Die Listings 6.1 und 6.3 weisen die gleiche main()-Struktur auf. Eine if-Anweisung wertet option aus, den Rückgabewert von menue_option_einlesen(). In Abhängigkeit vom Wert in der Variablen option gibt das Programm eine Meldung aus, bittet um die Eingabe einer Zahl und liest den Wert mittels scanf() ein. Beachten Sie den Unterschied zwischen den Zeilen 23, 29 und 35. Jede dieser Zeilen liest eine Variable ein, aber jede Zeile erwartet einen anderen Variablentyp. In den Zeilen 12 bis 14 werden die Variablen der entsprechenden Typen deklariert.

Wenn der Anwender die Menüoption zum Verlassen auswählt, gibt das Programm für alle drei Variablentypen die jeweils zuletzt eingegebene Zahl aus. Wenn der Anwender keinen Wert eingegeben hat, wird jeweils 0 ausgegeben, da in den Zeilen 12, 13 und 14 alle drei Typen mit 0 initialisiert wurden. Noch eine letzte Bemerkung zu den Zeilen 20 bis 36. Die hier verwendeten if-Anweisungen sind nicht besonders gut strukturiert. Sollten Sie der Meinung sein, dass eine if...else-Struktur hier besser angebracht wäre, möchte ich Ihnen nicht widersprechen. Am Tag 13, »Mit Bildschirm und Tastatur arbeiten«, werde ich Ihnen switch - eine weitere Anweisung zur Programmfluss-Steuerung - vorstellen. Diese Anweisung bietet sogar eine noch bessere Lösung.

Was Sie tun sollten

Was nicht

Verwenden Sie printf() und puts() zusammen mit scanf(). Nutzen Sie die Ausgabefunktionen, um den Anwender zur Eingabe von Werten aufzufordern, die dann mit scanf() eingelesen werden.

Vergessen Sie den Adressoperator (&) nicht, wenn Sie scanf()-Variablen verwenden.

Die Funktion scanf()

#include <stdio.h>
scanf( Formatstring[,Argumente,...]);

scanf() ist eine Funktion, die Konvertierungsspezifizierer in einem gegebenen Formatstring verwenden, um Werte in Variablen-Argumenten einzulesen. Als Argumente müssen die Adressen der Variablen und nicht die Variablen selbst übergeben werden. Im Falle von numerischen Variablen können Sie die Adresse übergeben, indem Sie den Adressoperator (&) vor den Variablennamen setzen. Die Verwendung von scanf() bedarf der Einbindung der Header-Datei stdio.h.

scanf() liest die Eingabefelder aus dem Standard-Eingabestrom, normalerweise die Tastatur. Sie legt jedes dieser eingelesenen Felder in einem Argument ab. Beim Ablegen der Informationen konvertiert die Funktion die Daten in das Format des zugehörigen Spezifizierers des Formatstrings. Zu jedem Argument muss ein Konvertierungsspezifizierer angegeben werden. Tabelle 6.2 enthält die gängigsten Konver-tierungsspezifizierer.

Beispiel 1

int x, y, z;
scanf( "%d %d %d", &x, &y, &z);

Beispiel 2

#include <stdio.h>
int main(void)
{
float y;
int x;
puts( "Geben Sie eine Fliesskommazahl ein und dann einen Integer" );
scanf( "%f %d", &y, &x);
printf( "\nIhre Eingabe lautete %f und %d ", y, x );
return 0;
}

Zusammenfassung

Mit der Beendigung der heutigen Lektion haben Sie das Rüstzeug, um Ihre eigenen C-Programme zu schreiben. Durch die Kombination der Funktionen printf(), puts() und scanf() und der Anweisungen zur Programmsteuerung, die bereits besprochen wurden, ist es Ihnen möglich, einfache Programme zu schreiben.

Für die Anzeige auf dem Bildschirm stehen Ihnen die Funktionen printf() und puts() zur Verfügung. puts() kann nur Text ausgeben, während printf() sowohl Text als auch Variablen ausgeben kann. Beide Funktionen verwenden Escape-Sequenzen zur Ausgabe von Steuerzeichen und Sonderzeichen.

Die Funktion scanf() liest einen oder mehrere Werte von der Tastatur ein und interpretiert sie gemäß den verwendeten Konvertierungsspezifizierern. Die eingelesenen Werte werden Programmvariablen zugewiesen.

Fragen und Antworten

Frage:
Warum sollte ich puts() verwenden, wenn printf() den gleichen beziehungsweise einen größeren Leistungsumfang als puts() hat?

Antwort:
Da printf() mehr kann, weist es auch mehr Overhead auf. Wenn Sie versuchen, ein kleines effizientes Programm zu schreiben, oder wenn Ihre Programme sehr groß und die Ressourcen immer wichtiger werden, nutzen Sie den geringen Overhead von puts(). Allgemein gilt, dass Sie möglichst ressourcen-schonend programmieren sollten.

Frage:
Warum muss ich stdio.h einbinden, wenn ich printf(), puts() oder scanf() verwende?

Antwort:
stdio.h enthält die Prototypen für die Standardein-/-ausgabefunktionen. printf(), puts() und scanf() sind drei dieser Standardfunktionen. Versuchen Sie einmal, ein Programm ohne die Header-Datei stdio.h auszuführen, und schauen Sie sich die Fehlermeldungen und Warnungen an, die Sie unweigerlich erhalten.

Frage:
Was passiert, wenn ich den Adressoperator (&) bei einer scanf()-Variablen vergesse?

Antwort:
Dieser Fehler kann sehr leicht passieren. Und unvorhersehbar sind die Ergebnisse. Wenn Sie Kapitel 9 und 13 gelesen haben und mehr über Zeiger wissen, werden Sie das besser verstehen. Im Moment reicht es, zu wissen, dass scanf() beim Fortlassen des Adressoperators die eingegebenen Informationen nicht in Ihrer Variablen, sondern an einer anderen Stelle im Speicher ablegt. Die Folgen reichen von »scheinbar ohne Auswirkungen« bis »Programmabsturz mit Fehlermeldung«. Zum Glück können Sie den gcc jedoch so einstellen, dass alle Warnungen angezeigt werden. Dann wird Ihnen mitgeteilt, wenn Sie vergessen haben, den Adressoperator zusammen mit einem Aufruf an scanf() zu verwenden.

Workshop

Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, sowie Übungen, die Sie anregen sollen, das Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Die Lösungen zu den Fragen und den Übungen finden Sie in Anhang C.

Quiz

  1. Welcher Unterschied besteht zwischen puts() und printf()?
  2. Wie lautet die Header-Datei, die Sie bei der Verwendung von printf() einbinden müssen?
  3. Was bewirken die folgenden Escape-Sequenzen?
  4. a. \\
  5. b. \b
  6. c. \n
  7. d. \t
  8. e. \a
  9. Welche Konvertierungsspezifizierer sollten verwendet werden, um folgende Daten auszugeben?
  10. a. Ein Zeichenstring
  11. b. Eine vorzeichenbehaftete Dezimalzahl
  12. c. Eine Fließkommazahl
  13. Welche Unterschiede bestehen bei Verwendung der folgenden Beispiele im literalen Text von puts()?
  14. a. b
  15. b. \b
  16. c. \
  17. d. \\

Übungen

Ab heute werden Sie mit Übungen konfrontiert, in denen Sie vollständige Programme zur Lösung bestimmter Aufgaben schreiben sollen. Da es jedoch immer mehr als eine Lösung in C gibt, sollten die Antworten am Ende des Buches nicht als die einzig korrekten betrachtet werden. Wenn Sie eigenen Code aufsetzen, der genau das macht, was gefordert war, umso besser! Wenn Sie Probleme haben, finden Sie vielleicht Hilfe in der Antwort. Die Antworten weisen nur wenige Kommentare auf, da es eine gute Übung ist, das Programm selbst nachzuvollziehen.

  1. Setzen Sie je eine printf()- und eine puts()-Anweisung auf, die eine neue Zeile beginnen.
  2. Setzen Sie eine scanf()-Anweisung auf, die ein Zeichen, eine vorzeichenlose Dezimalzahl und ein weiteres einfaches Zeichen einliest.
  3. Setzen Sie Anweisungen auf, die einen Integer einlesen und ausgeben.
  4. Ändern Sie Übung 3 dahingehend ab, dass nur gerade Zahlen (2 ,4 ,6 und so weiter) akzeptiert werden.
  5. Ändern Sie Übung 4 dahingehend ab, dass sie so lange Werte einliest, bis die Zahl 99 oder sechs gerade Zahlen eingegeben wurden. Speichern Sie die Zahlen in einem Array. (Hinweis: Sie benötigen eine Schleife).
  6. Wandeln Sie Übung 5 in ein ausführbares Programm um. Fügen Sie eine Funktion hinzu, die die Werte im Array getrennt durch Tabulatoren in einer einzigen Zeile ausgibt. (Geben Sie nur die eingegebenen Werte aus.)
  7. FEHLERSUCHE: Finden Sie den/die Fehler in folgendem Codefragment:
    printf( "Jack sagte, "Fischers Fritze fischt frische Fische."");
  8. FEHLERSUCHE: Finden Sie den/die Fehler im folgenden Programm:
    int hole_1_oder_2( void )
    {
    int antwort = 0;
    while (antwort < 1 || antwort > 2)
    {
    printf(1 für Ja, 2 für Nein eingeben);
    scanf( "%f", antwort );
    }
    return antwort;
    }
  9. Erweitern Sie die Funktion bericht_anzeigen() aus Listing 6.1 so, dass der Rest der Tabelle 6.1 ausgegeben wird.
  10. Schreiben Sie ein Programm, das zwei Fließkommazahlen von der Tastatur einliest und dann ihr Produkt ausgibt.
  11. Schreiben Sie ein Programm, das zehn Integer von der Tastatur einliest und dann deren Summe ausgibt.
  12. Schreiben Sie ein Programm, das Integer von der Tastatur einliest und sie in einem Array abspeichert. Das Einlesen sollte beendet werden, wenn eine Null eingegeben wurde oder das Ende des Arrays erreicht ist. Suchen Sie dann den größten und den kleinsten Wert im Array und zeigen Sie ihn an. (Achtung: Dieses Problem ist nicht ganz einfach, da Arrays noch nicht komplett behandelt wurden. Wenn Sie dabei Schwierigkeiten haben, versuchen Sie die gestellte Aufgabe nach Tag 7, »Numerische Arrays«, erneut zu lösen.)


vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbackKapitelanfangnächstes Kapitel


© Markt&Technik Verlag, ein Imprint der Pearson Education Deutschland GmbH