Ein- und Ausgabe über die Konsole

| ### Programmieren in C von Prof. Dr. Rainer Thomas

# 3. Ein- und Ausgabe über die Konsole

### 3.1 Allgemeines
3.2 Zeichenweise Ein- und Ausgabe
3.3 Formatierte Ein- und Ausgabe

## 3.1 Allgemeines

### Ein- und Ausgabe über die Konsole in C

- Die Sprache C selbst enthält keine Elemente zur Programm-Ein- und Ausgabe. Vielmehr muß jegliche Programm-Ein- und Ausgabe mittels Funktionen realisiert werden.
Daher sind in der - zu jedem C-System gehörenden - Standardbibliothek eine Reihe entsprechender Funktionen enthalten.
Durch die Normung der Standardbibliothek (ANSI-C-Bibliothek) ist bei Anwendung dieser Funktionen eine weitgehende Portabilität gewährleistet.
Allerdings existieren in vielen C-Bibliotheken neben den in der ANSI- Norm festgelegten Standard-Funktionen weitere -nicht genormte- Funktionen, deren Anwendung allerdings die Portabilität herabsetzt.
- Jegliche Ein- und Ausgabe in C geschieht über Dateien.
Geräte -wie die Konsole- werden dabei auch als Dateien behandelt.

In der Standardbibliothek sind einige -Geräten zugeordnete- Standard- Dateien definiert :

- | stdin | (Standard-Eingabe, Tastatur)
- | stdout | (Standard-Ausgabe, Bildschirm)
- | stderr | (Standard-Fehlerausgabe, Bildschirm)
| } | ANSI-C, KuR-C

- | stdaux | (Standard-Hilfsgerät, COM1)
- | stdprn | (Standard-Drucker, PRN, LPT1)
| } | zusätzlich in TURBO-C

Unter Bezugnahme auf die Standard-Dateien stdin und stdout kann somit eine Ein-/Ausgabe über die Konsole mit Hilfe der allgemeinen Dateibearbeitungs-Funktionen realisiert werden.

- Es existieren darüberhinaus aber für die Ein-und Ausgabe über die Konsole spezielle relativ einfach anwendbare Funktionen :

- Funktionen zur zeichenweisen Ein- und Ausgabe
(einschließlich Funktionen zur Ein- und Ausgabe von Zeichenketten)
- Funktionen zur formatierten Ein- und Ausgabe

Anmerkung : Mit Hilfe der in einigen Betriebssystemen (z.B. MS-DOS, UNIX) realisierten Umleitung der Standard-Ein- und Standard-Ausgabe auf der Kdo-Ebene kann mit diesen Funktionen auch eine -eingeschränkte- Bearbeitung anderer Dateien realisiert werden.
- Mit den Ein-/Ausgabefunktionen der Standard-Bibliothek eng verknüpft ist die Header-Datei

  `stdio.h`

In ihr sind die für die Anwendung der Funktionen benötigten Funktions- deklarationen (Function Prototypes) sowie einige Typen und Konstante (Makros), die mit der Realisierung und Anwendung der Funktionen in Zusammenhang stehen, definiert.
U.a. wird die Konstante

  `EOF`

definiert, die zur C-internen Kennzeichnung des Dateiendes dient.
Der Wert dieser int-Konstanten ist nicht mit dem Wert eines eventuellen im Betriebssystem verwendeten Dateiende-Zeichens (z.B. CTRL-Z) identisch, sondern beträgt i.a. -1.

Zur problemlosen und einfachen Anwendung der Standardbibliotheks-Funktionen ist es daher zweckmäßig die Header-Datei stdio.h mittels

  `#include <stdio.h>`

in das C-Programm-Modul einzubinden.

## 3.2 Zeichenweise Ein- und Ausgabe

### C-Standardbibliotheks-Funktionen zur zeichenweisen Ein- und Ausgabe von/nach "stdin"/"stdout"

    /* -------------------------------------------------------------------- */
    /*          getchar       -       Zeichenweise Eingabe von stdin        */
    /* -------------------------------------------------------------------- */

    #include <stdio.h>                 /* enthält Funktionsdeklaration */

    int getchar(void);

`getchar` liest das naechste Zeichen von stdin.

Funktionswert :
  das gelesene Zeichen (als int-Wert, mit führenden 0 ergänzt !)
bzw. `EOF` (= -1) bei Eingabe des Fileendezeichens für Textfiles oder im Fehlerfall

    /* -------------------------------------------------------------------- */
    /*          putchar       -       Zeichenweise Ausgabe nach stdout      */
    /* -------------------------------------------------------------------- */

    #include <stdio.h>                 /* enthält Funktionsdeklaration */

    int putchar(int c);
               /* c     auszugebendes Zeichen */

`putchar` gibt das Zeichen "c" (nach Umwandlung in unsigned char) nach stdout aus

Funktionswert :
  das ausgegebene Zeichen (als int-Wert, mit führenden 0 ergänzt !)
bzw. `EOF` (= -1) im Fehlerfall

### C-Standardbibliotheks-Funktionen zur Ein- und Ausgabe von Zeichenfolgen von/nach "stdin"/"stdout"

    /* -------------------------------------------------------------------- */
    /*          gets       -      Eingabe einer Zeichenfolge von stdin      */
    /* -------------------------------------------------------------------- */

    #include <stdio.h>                 /* enthält Funktionsdeklaration */

    char *gets(char *s);

                /* s   String zum Ablegen der gelesenen Zeichenfolge */

`gets` liest die nächsten Zeichen von stdin bis zum nächsten NL-Character ('\n') bzw bis das Dateiende erreicht ist.
Die gelesenen Zeichen werden in dem durch "s" referierten String - ohne eventuell gelesenen '\n'-Character - einschließlich eines angefügten '\0'-Characters abgelegt.

Funktionswert :

- | String "s"
- | bzw. NULL-Pointer bei Erreichen des Dateiendes ohne vorheriges Lesen von Zeichen oder im Fehlerfall

    /* -------------------------------------------------------------------- */
    /*        puts       -       Ausgabe eines Strings nach stdout          */
    /* -------------------------------------------------------------------- */

    #include <stdio.h>                 /* enthält Funktionsdeklaration */

    int puts(const char *s);

                /* s     auszugebender String */

`puts` gibt den durch "s" referierten String (ohne '\0'-Character !) nach stdout aus, wobei ein abschließender '\n'-Character angefügt wird.

Funktionswert :
  - ein nicht-negativer Wert bei Fehlerfreiheit
  - bzw. `EOF` (= -1) im Fehlerfall

### Weitere Funktionen der TURBO-C-Bibliothek zur zeichenweise Eingabe von "stdin"

    /* -------------------------------------------------------------------- */
    /*      getch     -     Zeichenweise ungepufferte Eingabe von stdin     */
    /* -------------------------------------------------------------------- */

    #include <conio.h>                 /* enthält Funktionsdeklaration */

    int getch(void);

`getch` liest das naechste Zeichen ungepuffert von stdin (und erzeugt keine Echo-Ausgabe).

Funktionswert :
  das gelesene Zeichen (als int-Wert, mit führenden 0 ergänzt !)
(Das Erreichen des Dateiendes bzw. das Auftreten eines Fehlers wird nicht durch ein spezielles Zeichen angezeigt)

Anmerkungen :
  - Die Eingabe von CTRL-Z wird nicht als Dateiende interpretiert
  - Diese Funktion ist keine ANSI-C-Funktion

    /* -------------------------------------------------------------------- */
    /*   getche  -   Zeichenweise ungepufferte Eingabe von stdio mit Echo   */
    /* -------------------------------------------------------------------- */

    #include <conio.h>                 /* enthält Funktionsdeklaration */

    int getche(void);

`getche` liest das naechste Zeichen ungepuffert von stdin und gibt es als Echo nach stdout aus.

Funktionswert :
  das gelesene Zeichen (als int-Wert, mit führenden 0 ergänzt !)
(Das Erreichen des Dateiendes bzw. das Auftreten eines Fehlers wird nicht durch ein spezielles Zeichen angezeigt)

Anmerkungen :
  - Die Eingabe von CTRL-Z wird nicht als Dateiende interpretiert
  - Diese Funktion ist keine ANSI-C-Funktion

## 3.3 Formatierte Ein- und Ausgabe

### C-Standard-Bibliotheks-Funktionen zur formatierten Ein- und Ausgabe von/nach "stdin"/"stdout"

    /* -------------------------------------------------------------------- */
    /*          scanf         -       Formatierte Eingabe von stdin         */
    /*--------------------------------------------------------------------- */

    #include <stdio.h>                /* enthält Funktionsdeklaration */

    int scanf(const char *ctrl, ...);

           /* ctrl   String zur Festlegung des Eingabeformats               */
           /* ...    weitere Parameter:  Pointer auf Variable,              */
           /*                            die Eingabewerte aufnehmen sollen  */

`scanf` liest die naechsten Zeichen von stdin, interpretiert sie entsprechend den im Steuerstring `ctrl` vorliegenden Typ- und Formatanangaben und weist die demgemaess konvertierten Werte den durch ihre Pointer (weitere Parameter !) referierten Variablen zu.

Die der Zeichen-Werte-Konvertierung zugrundeliegenden "Eingabefelder" werden durch White-Space-Character (Blank, Tab, Newline) bzw. durch Längenangaben im Steuerstring getrennt.

Funktionswert :

- | die Anzahl der erfolgreich zugewiesenen Werte
- | bzw. `EOF` (= -1), wenn - beim Lesen des ersten Wertes - versucht wurde über die Eingabe des Fileendezeichens für Textfiles hinaus zu lesen

Aufbau und Bedeutung des Steuerstrings `ctrl` siehe gesonderter Umdruck

    /* -------------------------------------------------------------------- */
    /*          printf        -       Formatierte Ausgabe nach stdout       */
    /*--------------------------------------------------------------------- */

    #include <stdio.h>                /* enthält Funktionsdeklaration */

    int printf(const char *ctrl, ...);

           /* ctrl   String zur Festlegung des Ausgabeformats               */
           /* ...    weitere Parameter:  Ausgabewerte, Anzahl und Typ ent-  */
           /*                    sprechend Konvertierungszeichen in "ctrl"  */

`printf` gibt die als weitere Parameter übergebenen Werte entsprechend den Formatangaben in `ctrl` als Zeichenfolgen nach stdout aus.

Funktionswert :
  Anzahl der ausgegebenen Zeichen

Aufbau und Bedeutung des Steuerstrings `ctrl` siehe gesonderter Umdruck

### Formatierte Ausgabe in C mit "printf"

- Allgemeine Form :

  `printf(controlstring, arg1, arg2, ... )`

- Beispiel :

  `printf("Laenge der Zeile = %d\n",laenge)`

- arg1, arg2, ... :

  auszugebende Werte (Argumente)
Anzahl und Typ sind durch "controlstring" festgelegt

- controlstring :

  Ausgabe von Text und Steuerung der Ausgabeformte, kann enthalten

- darstellbare Zeichen
- Zeichenersatzdarstellungen
- Umwandlungsspezifikationen

- Umwandlungsspezifikation :

  %[Formatangabe]Konvertierungszeichen

- Konvertierungszeichen :

c | Einzelzeichen
d, i | Integerzahl (dezimal,konegativ)
u | Integerzahl (dezimal,nur positiv)
o | Integerzahl (oktal, nur positiv, ohne führende "0")
x, X | Integerzahl (sedezimal, nur positiv, ohne führende "0x")
e, E | Gleitpunktzahl (float oder double) in Exponentendarstellung
f | Gleitpunktzahl (float oder double) in Dezimalbruchdarstellung
g, G | kürzeste Darstellung von e oder f
s | String
p | Pointer (implementierungsabh. Darst.)

- Formatangabe :

### Beispiele zur formatierten Ausgabe in C

    /* ------------------------------------------------------------------ */
    /* Programm FORMAUS                                                   */
    /* ------------------------------------------------------------------ */
    /* Beispiele fuer die formatierte Ausgabe mit "printf()"              */
    /* TURBO-C  2.0                                                       */
    /* ------------------------------------------------------------------ */

    #include<stdio.h>

    #define GRUSS    "hello, world"
    #define GRENZ    putchar(':')
    #define WRITELN  putchar('\n')

    void main(void)

    { char   zeich ='a';
      float  bruch = 3128.4503;
      double dopg  = 3128.4503146;
      int    ganz  = 641;
      int    ges = 14,  nach =4;
                                                       /*      Ausgabe      */

      GRENZ;  printf("%c",zeich);     GRENZ; WRITELN;  /* :a:               */
      GRENZ;  printf("%s",GRUSS);     GRENZ; WRITELN;  /* :hello, world:    */
      GRENZ;  printf("%d",ganz);      GRENZ; WRITELN;  /* :641:             */
      GRENZ;  printf("%f",bruch);     GRENZ; WRITELN;  /* :3128.450195:     */
      GRENZ;  printf("%f",dopg);      GRENZ; WRITELN;  /* :3128.450315:     */
      GRENZ;  printf("%e",bruch);     GRENZ; WRITELN;  /* :3.12845e+03:     */
      GRENZ;  printf("%e",dopg);      GRENZ; WRITELN;  /* :3.12845e+03:     */
      WRITELN;
      GRENZ;  printf("%10d",ganz);    GRENZ; WRITELN;  /* :       641:      */
      GRENZ;  printf("%010d",ganz);   GRENZ; WRITELN;  /* :0000000641:      */
      GRENZ;  printf("%-10d",ganz);   GRENZ; WRITELN;  /* :641       :      */
      GRENZ;  printf("%-010d",ganz);  GRENZ; WRITELN;  /* :641       :      */
      GRENZ;  printf("%3o",ganz);     GRENZ; WRITELN;  /* :1201:            */
      WRITELN;
      GRENZ;  printf("%12f",bruch);   GRENZ; WRITELN;  /* : 3128.450195:    */
      GRENZ;  printf("%012f",bruch);  GRENZ; WRITELN;  /* :03128.450195:    */
      GRENZ;  printf("%12.2f",bruch); GRENZ; WRITELN;  /* :     3128.45:    */
      GRENZ;  printf("%12e",bruch);   GRENZ; WRITELN;  /* : 3.12845e+03:    */
      GRENZ;  printf("%12.2e",bruch); GRENZ; WRITELN;  /* :     3.1e+03:    */
      GRENZ;  printf("%+*.*e",ges, nach, bruch);
                                      GRENZ; WRITELN;  /* :    +3.128e+03:  */
      WRITELN;
      GRENZ;  printf("%5s",GRUSS);    GRENZ; WRITELN;  /* :hello, world:    */
      GRENZ;  printf("%15s",GRUSS);   GRENZ; WRITELN;  /* :   hello, world: */
      GRENZ;  printf("%015s",GRUSS);  GRENZ; WRITELN;  /* :   hello, world: */
      GRENZ;  printf("%-15s",GRUSS);  GRENZ; WRITELN;  /* :hello, world   : */
      GRENZ;  printf("%15.5s",GRUSS); GRENZ; WRITELN;  /* :          hello: */
      GRENZ;  printf("%-15.5s",GRUSS);GRENZ; WRITELN;  /* :hello          : */
      WRITELN;
      GRENZ;  printf("%p",&bruch);    GRENZ; WRITELN;  /* :FFD6:            */
      GRENZ;  printf("%Np",&bruch);   GRENZ; WRITELN;  /* :FFD6:            */
      GRENZ;  printf("%Fp",(void far *)&bruch);
                                      GRENZ; WRITELN;  /* :1D04:FFD6:       */
    }

### Formatierte Eingabe in C mit "scanf"

- Allgemeine Form :

  `scanf(controlstring, arg1, arg2, ... )`

- Beispiel :

  `scanf("%2d %f %*d %d", &i, &zahl, &jwert)`

- arg1, arg2, ... :

  Zeiger auf Variable, deren Werte eingelesen werden sollen
Anzahl und Typ sind durch "controlstring" festgelegt

- controlstring :

  Festlegung der Anzahl der Eingaben und Interpretation (Typ, Format) der einzelnen Eingabefelder, kann enthalten

- Blanks, Tabs und Newlines (werden ignoriert)
- Umwandlungsspezifikationen

- Umwandlungsspezifikation :

- Konvertierungszeichen :

c | Zeichen(-folge) (auch blanks, tabs und newlines werden gelesen ) Default (keine Feldgrößenangabe): 1 Zeichen
d | Integer (dezimal)
i | Integer (dezimal) oder oktal (mit führender "0") oder sedezimal (mit führendem "0x" bzw "0X")
o | Integer (oktal, mit oder ohne führende "0")
x | Integer (sedezimal, mit oder ohne führendem "0x" bzw "0X")
u | Integer (dezimal, nur positiv)

e
f
g
| } | Gleitpunktzahl (beliebige Darstellung)

s | String (Ergänzung mit abschließendem '\0')
p | Pointer

h | vor | d,i,o,u,x | Kurze Integerzahl (short)
l | vor | d,i,o,u,x | Lange Integerzahl (long)
l | vor | e,f,g | double
L | vor | e,f,g | long double
N | vor | p | near pointer (TURBO-C)
F | vor | p | far pointer (TURBO-C)

- Beispiel :

    int   i, jwert;
    float zahl;
    ...
    scanf("%2d %f %*d %d",&i,&zahl,&jwert)

nach Eingabe : `56789 0123 457`
haben die Variablen folgende Werte :

i | `56` |
zahl | `789.0` | `0123` wird überlesen !
jwert | `457` |

### Einlesen von Strings mit "gets()" und "scanf()"

- Achtung :

Die beiden Funktionen `gets()` und `scanf()`
verhalten sich unterschiedlich beim Einlesen von Strings.

- `scanf()`

  betrachtet Blanks, Tabs und NLs als Kennzeichnung für ein Stringende
  -> Beendigung des Einlesens des Strings, keine Aufnahme dieser Zeichen in einen String

- `gets()`

  betrachtet nur NLs (und das Dateiende) als Kennzeichnung für ein Stringende (Eingabefeldende !)
  -> Blanks und Tabs werden mit eingelesen und in den String aufgenommen

==> | das Einlesen von Strings, die Blanks und/oder Tabs enthalten, ist nur mit `gets()`, nicht aber mit scanf() möglich.

- Demonstrationsbeispiel :

    /* ----------------------------------------------------------------- */
    /* Programm EINSTR                                                   */
    /* ----------------------------------------------------------------- */
    /* Demonstration des unterschiedlichen Verhaltens von                */
    /*           scanf() und                                             */
    /*           gets()                                                  */
    /* beim Einlesen von durch Blanks und/oder Tabs getrennten Strings   */
    /* ----------------------------------------------------------------- */

    #include <stdio.h>

    void main(void)
    {
      char zk[80];

      printf("\nEinlesen eines strings mit gets()  : ");
      gets(zk);
      printf("Gelesener String                   : %s\n", zk);
      printf("\nEinlesen eines strings mit scanf() : ");
      scanf("%s", zk);
      printf("Gelesener String                   : %s\n", zk);
    }

Bildschirmausgabe:

    E:\RT\C>einstr

    Einlesen eines strings mit gets()  : das ist ein Test
    Gelesener String                   : das ist ein Test

    Einlesen eines strings mit scanf() : das ist ein Test
    Gelesener String                   : das

    E:\RT\C>

Zum Inhaltsverzeichnis | Zum nächsten Abschnitt

###### Copyright © FH München, FB 04, Prof. Dr. Rainer Thomas
V - PC - 311 - 00 - TH - 01
V - PC - 321 - 00 - TH - 03
V - PC - 322 - 00 - TH - 01
V - PC - 324 - 00 - TH - 01
V - PC - 332 - 00 - TH - 05
V - PC - 341 - 00 - TH - 08
V - PC - 343 - 00 - TH - 07
V - PC - 344 - 00 - TH - 07
V - PC - 345 - 00 - TH - 02