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 = &PI; /* okay */ double *v = &PI; /* 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 = &PI; 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
© Copyright 2024 ExpyDoc