18.6 Zeichenweise Lesen und Schreiben – getchar und putchar
 
Um zeichenweise aus dem Stream stdin (Standardeingabe) zu lesen und zeichenweise auf stdout (Standardausgabe) zu schreiben, können folgende Funktionen verwendet werden:
#include <stdio.h>
// Lesen (zeichenweise) von stdin
int getchar();
// Schreiben (zeichenweise) auf stdout
int putchar(int c);
getchar() dient zum Einlesen einzelner Zeichen von der Standardeingabe, normalerweise ist dies die Tastatur. Ein wenig verwirrend dürfte der Rückgabewert der Funktion getchar() sein, da dieser vom Datentyp int ist. Das liegt daran, dass ein char vor der Verwendung eines Ausdrucks in ein int konvertiert wird.
Etwas genauer: Das Problem der Verwendung von int liegt in der Konstante EOF (End of File), welche das Ende einer Eingabe anzeigt. EOF ist eine define-Konstante, die in der Headerdatei <stdio.h> mit dem Wert –1 deklariert ist, damit diese nicht mit den normalen ASCII-Zeichen kollidiert. Früher, als noch 127 Zeichen verwendet wurden, war das kein Problem. Heute sind die Werte der Zeichen größer als 127, um zum Beispiel Umlaute wie ä, ö, ü und ß ausgeben zu können. Ist char dabei mit unsigned deklariert, könnten Zeichen zwischen 0 ... 255 Platz darin finden. Es ist dann aber kein Platz mehr für EOF (-1). Daher wurde einfach der Rückgabewert von getchar() als int deklariert, und damit können sowohl die 255 Zeichen als auch das EOF übermittelt werden – das Problem war gelöst.
Hierzu ein Listing:
/* echo_char.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int c;
while( (c = getchar()) !='.')
putchar(c);
return EXIT_SUCCESS;
}
Wenn hierbei mehrere Zeichen eingegeben werden und (¢) gedrückt wird, wird der Text Zeichen für Zeichen auf dem Bildschirm ausgegeben. Dies geschieht so lange, bis ein einzelnes Zeichen dem eines Punktes entspricht. Dann ist die while-Bedingung unwahr. Sie können als Abbruchbedingung auch EOF angeben:
while((c = getchar()) != EOF);
Hiermit werden solange Zeichen eingelesen, bis die Tastenkombination (Strg) + (Z) (unter MS-Systemen) oder (Strg) + (D) (unter Linux) gedrückt wird, welche EOF nachbildet.
Hinweis für Programmierneulinge Auch wenn es bei der Funktion getchar() den Anschein hat, dass hier mit ganzen Strings gearbeitet wird, ist dem nicht so. Diese Funktion liest Zeichen für Zeichen aus einem Puffer.
|
Dies geschieht aber erst, wenn die Taste ENTER gedrückt wird. Suchen Sie nach einer Funktion, die auf Betätigung einer bestimmten Taste wartet, könnte die Funktion getch() für Sie interessant sein. Für MS-DOS steht diese Funktion sofort zur Verfügung, z.B.: while( (c=getch()) != 'q');. Damit wird das Programm so lange angehalten, bis die Taste q gedrückt wird. Unter Linux müssen Sie dafür die Bibliothek <ncurses.h> oder <termios.h> verwenden. Der Nachteil von getch() ist, dass das Programm damit schlecht auf ein anderes System portiert werden kann.
|
Zur Funktion getchar() noch ein Listing:
/* count_char.c */
#include <stdio.h>
#include <stdlib.h>
int main (void) {
int c,counter=0;
printf("Bitte Eingabe machen:");
/* Eingabe machen bis mit Return beendet wird */
while((c=getchar()) != '\n') {
/* Leerzeichen und Tabulatorzeichen nicht mitzählen */
if( (c != ' ') && (c != '\t') )
counter++; /* counter erhöhen */
}
/* Gibt die Anzahl eingegeb. Zeichen von 0 bis counter-1 aus
* mit counter-1 wird das Zeichen '\0' nicht mitgezählt */
printf("Anzahl der Zeichen beträgt %d Zeichen\n", counter-1);
return EXIT_SUCCESS;
}
Mit diesem Listing werden alle darstellbaren Zeichen gezählt, die Sie über die Tastatur eingeben. Leerzeichen und Tabulatoren werden jedoch nicht mitgezählt.
18.6.1 Ein etwas portableres getch()
 
Diese Frage wurde mir bereits unzählige Male gestellt: Wie kann ich den Programmablauf anhalten, bis eine bestimmte Taste gedrückt wird? Dafür gibt es leider keinen standardisierten Weg. Aber um Sie jetzt nicht im Regen stehen zu lassen, folgt hierfür ein etwas portableres getch(), welches sowohl unter Linux/UNIX als auch unter MS-Windows funktioniert. Ihnen diese Funktion speziell unter Linux/UNIX näher zu erklären, würde eine Spur zu weit gehen. Falls es Sie dennoch interessiert, können Sie mehr darüber auf meiner Homepage unter http://www.pronix.de erfahren. Bei MS-Windows gibt es dabei nicht viel zu sagen, nur dass die Headerdatei <conio.h> mit eingebunden werden muss, da sich darin diese Funktion befindet. Hier der Quellcode:
/* portable_getch.c */
#include <stdio.h>
#include <stdlib.h>
/* ... übersetzt unter Linux/UNIX? */
#ifdef __unix__
#include <termios.h>
#include <unistd.h>
static struct termios new_io;
static struct termios old_io;
/* Funktion schaltet das Terminal in den cbreak-Modus: */
/* Kontrollflag ECHO und ICANON auf 0 setzen */
/* Steuerzeichen: Leseoperation liefert 1 Byte VMIN=1 VTIME=1 */
int cbreak(int fd) {
/*Sichern unseres Terminals*/
if((tcgetattr(fd, &old_io)) == –1)
return –1;
new_io = old_io;
/*Wir verändern jetzt die Flags für den cbreak-Modus*/
new_io.c_lflag = new_io.c_lflag & ~(ECHO|ICANON);
new_io.c_cc[VMIN] = 1;
new_io.c_cc[VTIME]= 0;
/*Jetzt setzen wir den cbreak-Modus*/
if((tcsetattr(fd, TCSAFLUSH, &new_io)) == –1)
return –1;
return 1;
}
int getch(void) {
int c;
if(cbreak(STDIN_FILENO) == –1) {
printf("Fehler bei der Funktion cbreak ... \n");
exit(EXIT_FAILURE);
}
c = getchar();
/*Alten Terminal-Modus wiederherstellen*/
tcsetattr(STDIN_FILENO, TCSANOW, &old_io);
return c;
}
/* ... oder wird das Programm unter MS-Windows übersetzt? */
#elif __WIN32__ || _MSC_VER || __MS_DOS__
#include <conio.h>
#endif
int main(void) {
int zeichen;
printf("Bitte 'q' drücken, um das Programm zu beenden!\n");
/* Wartet auf das Zeichen q */
while(( zeichen=getch() ) != 'q');
return EXIT_SUCCESS;
}
|