Zeichen, Zeichenketten, Datenströme

Grundlagen der Programmiersprache C für
Studierende der Naturwissenschaften
Teil 6: Zeichen, Zeichenketten, Datenströme
Patrick Schön
Abteilung für Angewandte Mathematik
Vorlesung vom 01. Juni 2015
Gliederung
Das const-Attribut
Zeichen
Zeichenketten
Datenströme
Gliederung
Das const-Attribut
Zeichen
Zeichenketten
Datenströme
Definition von Konstanten
Konstanten sind Variablen wie
double PI = 3.141592653589793115;
die im weiteren Verlauf nicht überschrieben werden sollen. Soche
Variablen können mit dem zusätzlichen Attribut const definiert
werden:
const double PI = 3.141592653589793115;
Eine Konstante muss mit ihrer Definition gleichzeitig initialisiert
werden!
Nach ihrer Definition dürfen Konstanten nicht mehr verändert werden:
const double PI = 3.141592653589793115;
PI *= 0.5; /* error */
Die letzte Anweisung führt zu einem Compiler-Fehler.
Zeiger auf Konstanten
Zeiger auf Konstanten müssen ebenfalls mit dem const-Attribut
versehen sein:
const double PI = 3.141592653589793115;
const double *u = Π /* okay */
double *v = Π /* error */
Auch über einen Zeiger darf der Wert einer const-Variablen nicht
geändert werden:
*u *= 0.5;
/* error */
Allerdings darf ein Zeiger im Programmverlauf auf verschiedene
konstante Größen verweisen:
const double PI = 3.141592653589793115;
const double u = Π
const double E = 2.718281828459045235;
u = &E;
Zeiger auf konstante Objekte als Funktionsargumente
Werden Zeiger an eine Funktion übergeben, so besteht die
Möglichkeit, dass ihr Inhalt von der Funktion geändert wird (call by
reference).
Eine Funktion kann signalisieren, dass sie ihre Argumente nicht
verändert. Ihre Argumente sind dann als const deklariert:
double two_norm ( const double *x, int len );
double determinant ( const double A[3][3] );
Argumente von primitiven Datentypen wie in
double sqrt ( double x );
sind in der Regel nicht const. Ihre Werte werden ohnehin nur in
Kopie übergeben (call by value).
Konstante Zeiger
Konstante Zeiger verweisen an eine feste Stelle im Speicher.
double x, y;
double *const ptr = &x;
ptr = &y; /* error */
Der Wert einer Variablen, auf die ein konstanter Zeiger verweist,
könnte sich allerdings ändern:
double x;
double *const u = &x;
*u = 1.;
Als abschließendes Beispiel hier die Definition eines konstanten
Zeigers auf ein konstantes Objekt:
const double y;
const double *const v = &y;
Gliederung
Das const-Attribut
Zeichen
Zeichenketten
Datenströme
Zeichen
Ein Zeichen ist ein Element der folgenden Zeichensätze:
I
Dezimalziffern:
0 1 2 3 4 5 6 7 8 9
I
Buchstaben des englischen Alphabets:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
I
Sonderzeichen:
! " # $ % & ( ) * = ‘ - . / : ; < = > ? [ \ ] ^ _
{ | } ~
I
Steuerzeichen (s. u.)
\n, \t, ...
Interne Darstellung von Zeichen
Computer speichern keine Zeichen, sondern ganze Zahlen. Durch
eine maschinenweite Zuordnung von Zeichen und darstellenden
Zahlen können diese richtig interpretiert werden.
Der ASCII-Code1 ist eine standardisierte Kodierung der oben
aufgelisteten Zeichen in 7 Bit.
In C gibt es zwei Integer-Datentypen, die jeweils ein Byte Speicher
benötigen:
signed char
unsigned char
Der Name char ist ein Alias für einen der beiden Datentypen. Er ist
zur Speicherung von Zeichen vorgesehen.
1 American
Standard Code for Information Interchange
ASCII-Tabelle
Zahlwert
Zeichen
Zahlwert
Zeichen
Zahlwert
Zeichen
Zahlwert
Zeichen
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
(blank)
!
”
#
$
%
&
’
(
)
*
+
,
.
/
0
1
2
3
4
5
6
7
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
8
9
:
;
<
=
>
?
@
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
ˆ
_
‘
a
b
c
d
e
f
g
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
{
|
}
˜
Tabelle : Liste der druckbaren ASCII-Zeichen (Buchstaben, Ziffern,
Satzzeichen und Sonderzeichen)
Zeichenkonstanten
Zeichenkonstanten stehen in einfachen Anführungszeichen:
’A’, ’1’, ’\n’
Beim letzten Beispiel handelt es sich um den Zeilenumbruch \n. Der
Umbruch gehört zu den sog. Steuerzeichen.
Eine char-Variable kann mit einem Zeichenkonstante oder einem
Integer-Wert initalsiert werden:
char c = ’A’;
/* char c = 89; */
Steuerzeichen
Steuerzeichen (engl. escape sequences) beginnen mit einem
Schrägstrich. Sie ersetzen andere Zeichen und oder können
Aktionen veranlassen.
Steuerzeichen
Bedeutung
\a
\b
\f
\n
\r
\t
\v
\"
\’
\?
\\
\nnn
\xhh
akustisches Signal
Cursor um eine Position nach links bewegen
Seitenvorschub
Zeilenumbruch
Cursor an den Zeilenanfang bewegen
Tabulatorzeichen
Vertikal-Tabulator
Ausgabe von ”
Ausgabe von ’
Ausgabe von ?
Ausgabe von \
oktale Zahl
hexadezimale Zahl
Formatierte Ausgabe mit printf
Zur Ausgabe von einzelnen Zeichen mit printf verwendet man das
Formatierungszeichen %c:
char c = ’A’;
printf("%c", c);
Intern wird ein Zeichen druch eine ganze Zahl repräsentiert.
Ausschlaggebend für die Ausgabe ist das Formatelement %c:
printf("%c", ’A’);
printf("%d", ’A’);
printf("%c", 89);
/* prints ’A’ */
/* prints 89 */
/* prints ’A’ */
Arithmetik mit Zeichen
Einige wenige arithmetische Operationen auf char-Größen sind
sinnvoll:
char c = ’T’;
c += ’a’ - ’A’;
printf("%c", c);
/* prints ’t’ */
Der obige Code ist äquivalent zu:
char c = 84;
c += 97 - 65;
printf("%c", c);
/* result is c = 116 */
/* prints ’t’ */
Achtung: Zwischen Zahlen und Zeichen, die lediglich Ziffern
darstellen, muss unterschieden werden:
char c = ’1’; /* ’1’ = 49 */
printf("’1’ + ’1’ = %d\n", d); /* prints 98 */
Bibliotheksfunktionen für Zeichen I
In der Standardbibliothek ctype.h sind eine Reihe von Funktionen
definiert, die Informationen über char-Variablen geben. Sie geben
den Wert 0 zurück, falls die überprüfte Eigenschaft nicht zutrifft.
Name
int
int
int
int
int
int
int
int
int
überprüfte Eigenschaft
isalnum(int c);
isalpha(int c);
isdigit(int c);
isblank(int c);
iscntrl(int c);
islower(int c);
isupper(int c);
isspace(int c);
isxdigit(int c);
c ist Buchstabe oder Ziffer
c ist Buchstabe
c ist Ziffer
c ist Leerzeichen oder Tabulator (neu in C99)
c ist Steuerzeichen
c ist Kleinbuchstabe
c ist Großbuchstabe
c ist \n, \t, \f, \v, \r oder Leerzeichen
c ist Hexadezimalziffer
Bibliotheksfunktionen für Zeichen II
Die Funktion toupper (ebenfalls in ctype.h enthalten) gibt das ihr
übergebene Zeichen als Großbuchstaben zurück, sofern es sich um
einen Kleinbuchstaben gehandelt hat.
int toupper(int c);
Andernfalls wird das Zeichen unverändert zurückgegeben.
Die Funktion tolower wandelt umgekehrt Großbuchstaben in
Kleinbuchstaben um:
int tolower(int c);
Der obige Beispielcode zu Rechenoperationen auf Zeichen lässt sich
nun gut verständlich ersetzen durch:
char c = ’T’;
c = tolower(c);
Gliederung
Das const-Attribut
Zeichen
Zeichenketten
Datenströme
Zeichenketten
Unter einer Zeichenkette (engl. String) verstehen wir eine Folge von
gültigen Zeichen, zum Beispiel:
"hello"
"lastName"
"+2}{_\n"
Im Prinzip ließen sich solche Zeichenketten in Feldern vom Typ char
speichern:
char str[5] = { ’h’, ’e’, ’l’, ’l’, ’o’ };
Das ist nicht sonderlich praktikabel: Die exakte Länge des Strings
müsste stets bekannt sein.
Interne Darstellung von Strings
In C behilft man sich mit einem Trick:
I
Strings werden tatsächlich als Felder vom Typ char gespeichert.
I
Die Länge des Feldes und die des Strings müssen aber nicht
unbedingt identisch sein.
I
Das Ende einer Zeichenkette wird durch ein besonderes
Terminierungszeichen, ’\0’, gekennzeichnet.
'h' 'e' 'l' 'l' 'o' '\0''X' 'Y' 'Z'
0
1
2
3
4
5
6
7
8
Stringkonstanten
Stringkonstanten sind Zeichenketten, die in doppelte
Anführungszeichen gesetzt sind:
"hello"
Ein Feld vom Typ char lässt sich mit einer Stringkonstanten
initialisieren:
char str[] = "hello";
Bei der Initialisierung eines char-Feldes mit einer Stringkonstanten
wird automatisch das Terminierungszeichen hinzugefügt. Das Feld
str belegt also 6 Byte.
Bedeutung des Trennungszeichens
Das Terminierungszeichen ’\0’ markiert das Ende eines Strings
(genauer: die Position nach dem letzten Element der Zeichenkette).
Anhand eines Beispiels illustrieren wir, wie das Terminierungszeichen
in Funktionen abgefragt wird und welche Auswirkungen sein Fehlen
haben kann.
Die folgende Funktion gibt die Länge eines Strings zurück:
int my_strlen(const char *str)
{
int len = 0;
while(str[len] != ’\0’)
++len;
return len;
}
Fehlt das Terminierungszeichen, wird im Beispiel die Schleife nie
verlassen und es kommt zu einer Bereichsüberschreitung!
Formatierte Ausgabe von Strings mit printf
Strings können mit printf sehr einfach ausgegeben werden:
char str[] = "hello";
printf("%s", str);
Auch printf sucht nach dem Terminierungszeichen:
1
#include <stdio.h>
2
3
4
5
int main(void)
{
char str[] = "I am a string.";
6
7
printf("%s\n", str);
/* prints "I am a string." */
str[4] = ’\0’;
printf("%s\n", str);
return 0;
/* prints "I am" */
8
9
10
11
12
}
Formatierte Ausgabe in Strings
In Zeichenketten kann mit sprintf geschrieben werden:
#include <cstdio.h>
int sprintf(char *str, const char *format, ...);
Das Terminierungszeichen \n am Ende der geschriebenen Zeichen
wird ergänzt.
Beispiel:
char str[128];
sprintf(str, "hello, %d", 123 );
/* str = "hello, 123\0..." */
Achtung: Der Speicher unter der angegebenen Adresse muss groß
genug sein, um die Zeichenkette abzuspeichern. Eine sichere
Variante ist snprintf.
Weitere Bibliotheksfunktionen für Strings I
Wir geben eine kurze Übersicht von Funktionen aus der
C-Standardbibliothek zum Umgang mit Strings an. Alle hier
beschriebenen Funktionen sind in der Datei string.h enthalten.
size_t strlen(const char *str);
Gibt die Anzahl der Zeichen des Strings zurück. Das Terminierungszeichen wird nicht mitgezählt.
char *strcpy(char *dest, const char *src);
Kopiert den String src in den String dest. Das terminierende
’\0’ wird mit kopiert.
char *strncpy(char *dest, const char *src, size_t n);
Wie strcopy, allerdings werden höchstens die ersten n Zeichen von src nach dest kopiert.
Weitere Bibliotheksfunktionen für Strings II
char *strcat(char *dest, const char *src);
Hängt den Inhalt von src an den String dest an. Voraussetzung ist, dass der Speicher unter dest dafür groß genug ist.
int strcmp(const char *str1, const char *str2);
Vergleicht die beiden Strings str1, str2 auf Ungleichheit.
Rückgabewert ist:
-1,
1,
0,
falls str1 lexikographisch kleiner ist als str2,
falls str1 lexikographisch größer ist als str2,
falls str1 und str2 identisch sind.
Umwandeln von Strings in numerische Datentypen
Enthält ein String eine Zahl wie z. B.
char istr[] = "123";
char fstr[] = "1.23";
kann man ihn in eine Integer- oder eine Gleitpunktzahl konvertieren.
Dazu gibt es in in der Datei stdlib.h die Funktionen:
int atoi(const char *str);
long int atol(const char *str);
double atof(const char *str);
Beispiel:
char istr[] = "123";
char fstr[] = "1.23";
int ival = atoi(istr);
double fval = atof(fstr);
Übergabe von Parametern beim Programmaufruf
Der Funktion main können – wie anderen Funktionen in C –
Parameter übergeben werden. Dies geschieht durch den User beim
Aufruf des ausführbaren Programms.
Das folgende Beispiel illustriert den Aufruf eines Programms a.out
unter UNIX mit Übergabeparametern "test" und "2.":
$ ./a.out test 2.
Übergabeparameter an main
Damit main Parameter übergeben werden können, muss die
Funktion wie folgt definiert werden:
int main(int argc, char *argv[])
{
...
}
Sämtliche Kommandozeilenparameter werden als Zeichenketten
übergeben:
I
Der Parameter argv ist ein Feld von Zeigern auf Zeichenketten,
die jeweils einen Übergabeparameter in der Reihenfolge ihrer
Eingabe enthalten.
I
Die Anzahl der Argumente ist in der Variablen argc gespeichert.
I
Der erste String argv[0] enthält den Namen der ausführbaren
Datei selbst (also ist immer argc ≥ 1).
Übergabeparameter an main
Im folgenden einfachen Beispiel werden die Übergabeparameter auf
der Konsole ausgegeben:
Beispiel:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i = 0;
for( ; i < argc; ++i)
printf("%s\n", argv[i]);
return 0;
}
Ausgabe:
$ ./a.out test 2.
a.out
test
2.
Formatierte Eingabe von Strings mit scanf
Die Funktion scanf ist nur bedingt zum Einlesen von Strings
geeignet.
Betrachten wir das folgende Beispiel:
1
#include <stdio.h>
2
3
4
5
6
7
8
9
10
int main(void)
{
char name[25];
printf("Enter name: ");
scanf("%s", name);
printf("hello, %s\n", name);
return 0;
}
Führt man das Programm aus, so stellt man fest, dass nur
zusammen- hängende Zeichenketten ohne Leerzeichen eingelesen
werden:
$ ./a.out
Enter name: Max Mustermann
hello, Max
Einlesen von Strings mit gets
In der Datei stdio.h ist folgende Funktion zum Einlesen von Srings
definiert:
char *gets(char *str);
Die Funktion ist allerdings gefährlich: Es kann nicht überprüft werden,
ob der Speicher unter der angegebenen Adresse groß genug für die
Eingabe ist.
Beispiel:
1
#include <stdio.h>
2
3
4
5
6
7
8
9
10
int main(void)
{
char name[20];
printf("Enter name: ");
gets(name);
printf("hello, %s\n", name);
return 0;
}
Gliederung
Das const-Attribut
Zeichen
Zeichenketten
Datenströme
Datenströme I
Bislang ist in allen unseren Programmen die Ein- und Ausgabe von
Daten über die Konsole erfolgt.
Anstatt einen Text auf dem Bildschirm anzuzeigen, könnten dieselben
Daten auch in eine Datei geschrieben oder an einen Drucker
gesendet werden.
<mypc:~>
Eingabe
Programm
Ausgabe
filename
Lorem ipsum
Ebenso könnte die Aufgabe lauten, Daten aus einer Datei oder von
einem Messgerät einzulesen.
Datenströme II
Der Ein- und Ausgabe in C liegt ein einheitliches abstraktes Modell zu
Grunde: das des Datenstroms (engl. stream).
Wir werden sehen, wie neue Ströme geöffnet (und wieder
geschlossen) werden, um Daten in Dateien zu schreiben oder aus
Dateien zu lesen.
Mit Dateien verbundene Ströme sind die wichtigsten Ströme in C.
Ströme haben – wie jedes andere Objekt in C – einen Typ. Aus
historischen Gründen lautet er in C
FILE *
Standarddatenströme
Zu Beginn eines jeden C-Programms werden die folgenden Ströme
(engl. standard streams) automatisch geöffnet:
Standardeingabe
Standardausgabe
Standardfehlerausgabe
stdin
stdout
stderr
zeilenweise gepuffert
zeilenweise gepuffert
nicht gepuffert
Ihr Typ ist jeweils FILE *.
stdin ist für gewöhnlich mit der Tastatur, stdout und stderr
werden auf dem Bildschirm ausgegeben:
stdout
stdin
Programm
stderr
<mypc:~>
Öffnen von Dateien I
Mit der Funktion fopen wird eine Datei geöffnet:
FILE *fopen(const char *filename, const char *mode);
→ Der Parameter filename enthält den Namen der zu öffnenden
Datei.
→ Der zweite Parameter mode gibt an, wie auf die Datei zugegriffen
werden soll: ob sie nur gelesen, geschrieben oder gelesen und
geschrieben werden soll (s. u.).
→ Rückgabewert von fopen ist ein FILE-Zeiger, d. h. ein neuer
Datenstrom. Konnte die angegebene Datei nicht geöffnet
werden, ist der Rückgabewert gleich Null.
Öffnen von Dateien II
Das zweite Argument von
FILE *fopen(const char *filename, const char *mode);
gibt an, wie auf eine neue oder bereits existierende Datei zugegriffen
werden soll.
Für die Zeichenfolge mode sind folgende Angaben zulässig:
"r"
(read)
Eine bereits existierende Datei soll zum Lesen geöffnet werden.
"w"
(write)
Eine neue Datei soll zum Schreiben geöffnet werden. Existiert die Datei bereits, wird ihr Inhalt gelöscht.
"a"
(append)
Eine bestehende Datei soll zum Schreiben am Dateiende geöffnet
werden. Existiert die Datei nocht nicht, wird sie neu angelegt.
"r+"
Eine bestehende Datei soll zum Schreiben und Lesen geöffnet
werden.
"w+"
Eine neue Datei soll zum Schreiben und Lesen geöffnet werden. Existiert die Datei bereits, wird ihr Inhalt gelöscht.
"a+"
Eine bestehende Datei soll zum Schreiben und Lesen am Dateiende
geöffnet werden. Existiert die Datei nocht nicht, wird sie neu angelegt.
Schließen von Dateien
Eine nicht mehr benötigte Datei (allgemeiner ein Datenstrom) wird mit
int fclose(FILE *file);
geschlossen.
Rückgabewert der Funktion ist Zahl Null, falls das Schließen
erfolgreich war. Im Fehlerfall gibt fclose das Zeichen EOF (engl. end
of file) zurück:
FILE *file = fopen("text.txt", "r");
...
if(fclose(file) == EOF)
{
/* error */
...
}
Beispiel: Öffnen und Schließen von Dateien
Die unten stehende Funktion prüft, ob sich die angegebene Datei
zum Lesen öffnen lässt.
1
2
3
4
/* returns 0, if file can’t be read */
int exists(const char *filename)
{
FILE *file = fopen(filename, "r");
5
if(file)
{
fclose(file);
return 1;
}
6
7
8
9
10
11
return 0;
12
13
}
Funktionen zur formatierten Ausgabe
Für die Ausgabe von Text auf der Konsole kennen wir die Funktion
int printf(const char *format, ...);
Es gibt eine eine Verallgemeinerung für FILE-Zeiger:
int fprintf(FILE *file, const char *format, ...);
Beide Funktionen erzeugen den gleichen Output, nur dass printf
ausschließlich nach stdout schreibt, während fprintf in den
übergebenen Ausgabe-Stream file schreibt.
Es sind daher äquivalent:
printf("hello");
fprintf(stdout, "hello");
Schreiben in Dateien
Das folgende Beispiel illustriert die Verwendung von fprintf.
Insbesondere können Variablen oder Konstanten wie mit printf
ausgegeben werden.
1
#include <stdio.h>
2
3
4
5
6
7
int main(void)
{
FILE *output = fopen("example.txt", "w");
if(!output)
return 1;
8
fprintf(output, "hello, world");
fprintf(output, "2. + 2. = %f\n", 2. + 2.);
9
10
11
fclose(output);
return 0;
12
13
14
}
Der Datenstrom stderr
Der Strom stderr ist dafür da, Fehlermeldungen von normalem
Programmoutput zu trennen:
1
#include <stdio.h>
2
3
4
5
6
7
8
9
10
11
int main(void)
{
char message[] = "everything is fine\n";
char error[] = "this is an error message\n";
printf("%s", message);
fprintf(stdout, "%s", message);
fprintf(stderr, "%s", error);
return 0;
}
Umleiten von Strömen in der Unix-Shell
Die Standardströme finden sich in der Unix-Shell wieder. Ihnen sind
Nummern zugeordnet:
0
1
2
stdin
stdout
stderr
Die Ausgabeströme können umgeleitet werden, um so regulären
Output von Fehlermeldungen zu trennen:
$ ./print 1>> output.txt
$ ./print 2>> errors.txt
(regulären Output in output.txt schreiben)
(Fehler in errors.txt schreiben)
Der Output eines Stroms kann gänzlich unterdrückt werden:
$ ./print > /dev/null
this is an error message
Funktionen zur formatierten Eingabe
Auch für die Funktion scanf gibt es eine Verallgemeinerung:
int scanf(const char *format, ...);
int fscanf(FILE *file, const char *format, ...);
fscanf liest aus dem mit file bezeichneten Strom ein. Die
Funktion scanf ist nur ein Spezialfall von fscanf, und liest nur von
der Standardeingabe stdin ein.
Also sind äquivalent:
int a;
scanf("%d", &a);
fscanf(stdin, "%d", &a);
Pufferung I
Es ist im allgemeinen nicht effizient, einzelne Zeichen zu lesen oder
zu schreiben. Stattdessen werden Daten gepuffert.
Der Puffer ist ein Bereich im Arbeitsspeicher, in dem Zeichen
gesammelt werden, um später als Block übertragen zu werden.
Folgende drei Arten der Pufferung gibt es für Ströme:
I
vollständig gepuffert
Die Zeichen im Puffer werden gewöhnlich erst dann übertragen,
wenn der Puffer voll ist.
I
zeilenweise gepuffert
Die Zeichen im Puffer werden übertragen, wenn ein
Newline-Zeichen im Puffer eintrifft oder der Puffer voll ist.
I
ungepuffert
Zeichen werden sofort übertragen.
Pufferung II
Zeilenweise gepufferte Ausgabeströme werden erst geleert, wenn ein
Zeilenumbruch gelesen wird.
1
2
#include <unistd.h>
#include <stdio.h>
3
4
5
6
7
8
9
2
#include <unistd.h>
#include <stdio.h>
3
int main(void)
{
/* print immediately */
printf("hello\n");
/* wait 3 seconds */
sleep(3);
10
4
5
int main(void)
{
6
printf("hello");
7
8
sleep(3);
printf("\n");
/* print text */
return 0;
9
10
11
11
return 0;
12
13
1
}
12
13
}
Pufferung III
Auch Steuerzeichen landen im Puffer. Das folgende Beispiel
funktioniert daher nicht wie beabsichtigt: statt eines zweiten Zeichen
wird der Zeilentrenner ’\n’ aus dem Puffer gelesen.
1
#include <stdio.h>
2
3
4
5
int main(void)
{
char c, d;
6
printf("enter first character: ");
scanf("%c",&c);
printf("enter second character: ");
scanf("%c",&d);
7
8
9
10
11
printf("input: %c and %c \n", c, d);
12
13
return 0;
14
15
}
Zeichen lesen
Zum Lesen eines einzelnen Zeichens gibt es folgende Funktionen:
int fgetc(FILE *file);
int getc(FILE *file);
int getchar();
Die Funktion fgetc liest ein Zeichen von dem Eingabestream, der
mit file verknüpft ist. Der Rückgabewert ist das gelesene Zeichen
oder EOF falls ein Fehler aufgetreten ist.
getc ist ein Makro, das wirkungsgleich mit fgetc ist. Im Normalfall
kann man das Makro vorziehen.
Auch getchar ist ein Makro. Es ist äquivalent zu getc(stdin).
Beispiel:
FILE *file = fopen("input.txt", "r");
int c = getc(file);
int d = getchar();
Ein Zeichen zurückstellen
Ein zu viel gelesenes Zeichen kann wieder an einen Stream
zurückgegeben werden. Dazu dient die folgende Funktion:
int ungetc(int c, FILE *file);
Der Funtionsaufruf bewirkt, dass das Zeichen c in den Stream
zurückgestellt wird, auf den file verweist. Bei den nächsten
Leseoperationen werden zuerst die zurückgestellten Zeichen in
umgekehrter Reihenfolge gelesen.
Beispiel:
int c, d;
c = getc(stdin);
ungetc(c, stdin);
d = getc(stdin); /* c == d */
Zeichen schreiben
Die folgenden Funktionen schreiben ein einzelnes Zeichen in einen
Stream:
int fputc(int c, FILE *file);
int putc(int c, FILE *file);
int putchar(int c);
Die Funktion fputc schreibt das Zeichen c in den Stream, auf den
file zeigt. Der Rückgabewert ist das geschriebene Zeichen oder
EOF im Fehlerfall.
Das Makro putc ist wirkungsgleich mit fputc. Das Makro putchar
ist äquivalent zu putc(stdout).
Beispiel:
int c;
c = getc(stdin);
putc(c, stdout);
putc(c, stderr);
Beispiel: Den Eingabepuffer leeren
Mit den eben gezeigten Funktionen können wir das obige zum
Einlesen zweier Zeichen von der Konsole korrigieren:
Quelltext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
int myfflush(FILE *file)
{
int c;
while((c = fgetc(file) != ’\n’) && c != EOF) ;
return 0;
}
int main(void)
{
int c, d;
printf("enter first character: ");
c = getchar();
myfflush(stdin);
printf("enter second character: ");
d = getchar();
myfflush(stdin);
printf("input: %c and %c \n", c, d);
return 0;
}
Einlesen von Strings
Oben haben wir als unsicher beschriebene Funktion gets
kennengelernt. Soll ein String aus einem Eingabestrom (z. B. stdin)
eingelesen werden, ist die Funktion fgets aus stdio.h die bessere
Wahl:
char *fgets(char *str, int num, FILE *file);
Das Argument num gibt die maximal einzulesende Zahl von Zeichen
(inklusive des Terminierungszeichens) an. Im Fehlerfall gibt fgets
einen Null-Zeiger zurück.
Beispiel:
char name[32];
fgets(name, 32, stdin);
Schreiben von Strings
Um einen Null-terminierten String in einen Stream zu schreiben, gibt
es folgende Funktionen:
int fputs(const char *string, FILE *file);
int puts(const char *string);
Rückgabewert beider Funktionen ist ein nicht-negativer Wert, falls
kein Fehler aufgetreten ist, und EOF sonst.
fputs schreibt ein übergebenen String in den Ausgabe-Stream, der
mit file verknüpft ist. Das abschließende Null-Zeichen wird nicht in
den Ausgabe-Stream geschrieben.
puts gibt den String auf die Standardausgabe aus und zusätzlich ein
Newline-Zeichen.
Autoren
Autoren die an diesem Skript mitgewirkt haben:
I
2011–2014 : Christoph Gersbacher
I
2014–2015 : Patrick Schön
This work is licensed under a Creative Commons
Attribution-ShareAlike 4.0 International (CC
BY-SA 4.0) License.
http://creativecommons.org/
licenses/by-sa/4.0/legalcode