scanf in C drei Zeichen einlesen

OP #3868078
Lesenswert?

Hallo,

diesmal geht's darum, drei Zeichen mit scanf einzulesen. Ich habe zwei 
Versionen, wobei Version 1 nicht geklappt hat. Dann habe ich weiter 
ausprobiert und kam auf die zweite Version, in dem ich alle Zeichen auf 
einmal eingelesen habe. Wo liegt der Fehler bei der ersten Version?

Mein erster Versuch:
1
#include <stdio.h>
2
int main(void)
3
 {
4
    char x,y,z;
5
    printf("Bitten geben Sie das 1.Zeichen ein: \n");
6
    scanf("%c",&x);
7
    printf("Bitten geben Sie das 2.Zeichen ein: \n");
8
    scanf("%c",&y);
9
    printf("Bitten geben Sie das 3.Zeichen ein: \n");
10
    scanf("%c",&z);
11
    return 0;
12
}
Mein zweiter Versuch:
1
#include <stdio.h>
2
int main(void)
3
 {
4
    char x,y,z;
5
    printf("Bitte 3 Zeichen eingeben: \n");
6
    scanf("%c %c %c", &x,&y,&z);
7
    return 0;
8
}
#3868100
Lesenswert?

Der Fehler bei deinem ersten Versuch liegt darin, dass du ja nicht 3 
Zeichen eingibst, sondern deren 6.
Du tippst natürlich die 3 Zeichen, die du eingeben willst. Aber: Du 
tippst dazwischen bzw. nach dem letzten ja auch jedesmal auf 'Return'. 
Und auch dieses jeweilige Return ist ein Zeichen, das du bzw. das 
Programm behandeln musst. Es wird dir ganz normal als eine gültige 
Eingabe für %c geliefert.
OP #3868121
Lesenswert?

Achso Dankeschön :)
Nur eine Sache, die ich nicht ganz verstehe, warum kommt es bei Nutzung 
von int und Eingabe von ganzen Zahlen nicht zu dieser Pufferung?
1
int main(void)
2
 {
3
    int x,y,z;
4
    printf("Bitten geben Sie das 1.Zeichen ein: \n");
5
    scanf("%d",&x);
6
    printf("Bitten geben Sie das 2.Zeichen ein: \n");
7
    scanf("%d",&y);
8
    printf("Bitten geben Sie das 3.Zeichen ein: \n");
9
    scanf("%d",&z);
10
    return 0;
11
}
#3868132
Lesenswert?

Leyla S. schrieb:
> Achso Dankeschön :)
> Nur eine Sache, die ich nicht ganz verstehe, warum kommt es bei Nutzung
> von int und Eingabe von ganzen Zahlen nicht zu dieser Pufferung?

Weil ein %d sich automatisch soweit vortastet, bis es zu einer Zahl 
kommen kann. D.h das %d überliest selbsttätig den Return und eventuelle 
andere Leerzeichen (sog. Whitespace-Zeichen).
Ein %c tut das aber nicht. Der liefert dir genau das nächste Zeichen, 
welches im Eingabestrom daher kommt.
Moderator #3868203
Lesenswert?

Karl Heinz schrieb:
> Leyla S. schrieb:
>> Okey danke für den Hinweise mit fflush(stdin). Das erste klappt jetzt:)
>
> Ist aber genau genommen nicht garantiert, auch wenn viele
> Implementierungen das so handhaben.
> fflush ist eigentlich nur für Ausgabe-Streams definiert. Was passiert,
> wenn man fflush auf einen Eingabe-Stream anwendet ist
> implementierungs-abhängig.

Schlimmer noch: Es ist sogar undefined Behavior. fflush sollte deswegen
überhaupt nicht auf Eingabeströme angewandt werden.

Hier der entsprechende Auszug aus dem Standard:
1
Description
2

3
If stream points to an output stream or an update stream in which the
4
most recent operation was not input, the fflush function causes any
5
unwritten data for that stream to be delivered to the host environment
6
to be written to the file; otherwise, the behavior is undefined.
7

8
If stream is a null pointer, the fflush function performs this flushing
9
action on all streams for which the behavior is defined above.

Auf meinem Linux-Rechner hier passiert bei fflush(stdin) einfach gar
nichts, aber selbst ein Systemabsturz bei diesem Aufruf wäre
standardkonform.

Hier sind noch zwei FAQs (mit Antworten ;-)) zu dem Thema:

  http://c-faq.com/stdio/stdinflush.html
  http://c-faq.com/stdio/stdinflush2.html

Im konkreten Fall kann man das CR-Zeichen und ggf. weiteren Whitespace
dadurch überlesen, dass man in den Formatstrings jeweils vor dem %c noch
ein Leerzeichen einfügt:
1
    scanf(" %c",&x);

Damit kann man dann allerdings auch keine Leerzeichen mehr einlesen. Da
scanf alle Whitespace-Zeichen (Leerzeichen, Tab, CR, LF usw.) gleich
behandelt, ist es zum Einlesen von solchen Zeichen ziemlich ungeeignet.
Man nimmt dann lieber getchar (zum Einlesen einzelner Zeichen) oder
fgetc (zum Einlesen ganzer Zeilen).
#3868240
Lesenswert?

Yalu X. schrieb:
> Man nimmt dann lieber getchar

Das nehm ich auch ganz gerne.
1
int main(void)
2
{
3
    char x, y, z;
4

5
    printf("Bitten geben Sie das 1.Zeichen ein: \n");
6
    do { scanf("%c",&x); }
7
    while (getchar() != '\n');
8
    printf("Bitten geben Sie das 2.Zeichen ein: \n");
9
    do { scanf("%c",&y); }
10
    while (getchar() != '\n');
11
    printf("Bitten geben Sie das 3.Zeichen ein: \n");
12
    do { scanf("%c",&z); }
13
    while (getchar() != '\n');
14
    return 0;
15
}
#3868275
Lesenswert?

Yalu X. schrieb:

>> fflush ist eigentlich nur für Ausgabe-Streams definiert. Was passiert,
>> wenn man fflush auf einen Eingabe-Stream anwendet ist
>> implementierungs-abhängig.
>
> Schlimmer noch: Es ist sogar undefined Behavior.


War mir nicht mehr sicher.

> Man nimmt dann lieber getchar (zum Einlesen einzelner Zeichen) oder
> fgetc (zum Einlesen ganzer Zeilen).

Du meinst wohl fgets

So haben wir das im Grunde auch meistens gehandhabt. Mit fgets eine 
Zeile einlesen und dann mit sscanf oder sonstigen Mittel zerlegen. scanf 
bzw. fscanf können zwar benutzt werden, wenn man genau definierte 
Eingaben hat, aber im Grunde ist eine fgets/parsing Kombination meistens 
sicherer.
Wobei sich mit den 'neueren' Formatieroptionen da auch einiges geändert 
hat. Aber wie es so schön heisst: Ein alter Hund lernt keine neuen 
Tricks mehr. "fgets, dann parsing" hat sich bei mir bewährt. Sofern 
nicht überhaupt plattformspezifische Methoden zum Zug kommen müssen, 
weil so Dinge wie Funktionstasten od. Cursortasten da auch noch 
mitgenommen werden müssen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren