Forum: PC-Programmierung C problem mit scanf und "Enter"


von Sascha (Gast)


Lesenswert?

Hi Leute,

Ich sitz gerade an einem C Projekt und muss dazu sagen, dass ich ein 
ziemlicher Anfänger in C bin.
Das konkrete Problem sieht so aus, dass mein Programm auffordert, 
verschiedene Werte einzugeben und dann Berechnungen dazu anstellt.
wir haben jetzt nach einigen fehlversuchen, bei denen char Variabeln 
"falsch" eingelesen wurden, festgestellt, dass bei einem scanf befehl 
auf einen char, zuerst das letzte "Enter" eingelesen wird, das noch von 
der Bestätigung der letzten Eingabe "im Raum schwebt". Der einzige 
Lösungansatz, den wir ergoogeln konnten ist, die "Enter" mit getchar() 
abzufangen und quasi ins Nirvana zu schicken.
Aber gibts da keine elegantere Lösung?

Wäre sehr froh über eure Hilfe,

Grüße

Sascha

von René H. (Gast)


Lesenswert?

getline() statt scanf()

Grüsse,
René

von Theor (Gast)


Lesenswert?

Am besten den Code zeigen und das OS nennen.

Aber allgemein ist <return> auch ein Zeichen - und nicht ausschliesslich 
, wie man spontan annehmen könnte - irgendein "Kontrollknopf für das 
System" der Eingaben beendet.
Da Ihr, - wie ich ohne den Code nur annehmen kann -, ein einzelnes 
Zeichen mit scanf lest, gibt das System zwar ein einzelnes Zeichen 
weiter; es ist zunächst etwas verwirrend, dass <return> noch dazu auch 
diesen Weitergabe-Vorgang anstösst. Aber das <return->-Zeichen ist immer 
noch im Buffer und wird daher beim nächsten scanf eines Zeichens, als 
nächstes weitergegeben.

von Sascha (Gast)


Lesenswert?

1
#include <stdio.h>
2
#include <math.h>
3
4
int main(){
5
    char c;
6
    int i;
7
    double A[10];
8
    
9
    do{
10
        printf("Summe[+] oder Produkt[*]?\n");
11
        scanf("%c", &c);
12
        /**getchar();**/
13
        printf("Startwert Eingeben:\n");
14
        scanf(" %lf", &A[0]);
15
        if(A[0] == 0){
16
            printf("Startwert darf nicht Null sein");
17
        }
18
            else{
19
                switch(c){
20
                case '+':
21
                    for(i=1;i<=10;i++){
22
                    A[i] = A[i-1] + A[0];
23
                    printf("%lf\n", A[i-1]);
24
                    }
25
                    break;
26
                case '*':
27
                    for(i=1;i<=10;i++){
28
                    A[i] = A[i-1] * A[0];
29
                    printf("%lf\n", A[i-1]);
30
                    }
31
                    break;
32
                default: 
33
                printf("Sie waren zu dumm, die erste Eingabe zu verstehen. Bitte fahren Sie das System herunter und benutzen Sie nie wieder einen PC\n");
34
                }
35
            }
36
        printf("Moechten Sie beenden?\n");
37
        /**getchar();**/
38
        scanf(" %c", &c);
39
        getchar();
40
    }while(c != 'j');
41
    }

Also das ist der Code. wir sind jetzt darauf gekommen, dass wir die 
ersten 2 getchar() nicht mehr brauchen, da wir einfach bei scanf vor der 
flag eine leerstelle lassen, die dann das return frisst. komischerweise 
funktioniert es aber andersrum nicht, also mit leerstelle nach der flag. 
daher muss das letzte getchar auch nach wie vor aktiv bleiben, da unsere 
variable c ansonsten im nächsten loop direkt wieder mit return belegt 
werden würde und das programm dann nicht mehr funktioniert.

: Bearbeitet durch User
von Theor (Gast)


Lesenswert?

Nun. Ich muss da mal grinsen. :-}

Das ist, meiner Meinung nach, allenfalls ein "Würgaround", auf den Ihr 
durch raten gekommen seid, aber keine gedankliche Ableitung aus der 
Beschreibung von scanf oder getc. (Offen gesagt, ist mir das noch nie 
begegnet und ich habe es auch nie selbst so gemacht).
Als Lehrer würde ich das, ohne eine Erklärung, wie sich das aus der 
Spezifikation und Implementierung von scanf ergibt, um eine Note 
abwerten.

Ihr habt hier vier Möglichkeiten (abgesehen von Eurer Lösung):

1. Renès Lösung mit getline, wenn Ihr nichts verstehen wollt, sondern 
nur die Aufgabe lösen.

2. Die Implementierung von getline anschauen - um zu lernen wie das 
zusammenhängt. Kann zu Punkt 3 oder 4 führen.

3. Versuchen, das Problem korrekt (wie ich meine) mit scanf/flush bzw. 
dem Terminal-Mode zu lösen - nicht einfach aber lehrreich.

4. Eine eigene, explizit hingeschriebene Lösung mit getc implementieren 
- nicht einfach, aber lehrreich.

Beitrag #5434301 wurde vom Autor gelöscht.
von Dirk B. (dirkb2)


Lesenswert?

Sascha schrieb:
> Also das ist der Code. wir sind jetzt darauf gekommen, dass wir die
> ersten 2 getchar() nicht mehr brauchen, da wir einfach bei scanf vor der
> flag eine leerstelle lassen, die dann das return frisst. komischerweise
> funktioniert es aber andersrum nicht, also mit leerstelle nach der flag.
> daher muss das letzte getchar auch nach wie vor aktiv bleiben, da unsere
> variable c ansonsten im nächsten loop direkt wieder mit return belegt
> werden würde und das programm dann nicht mehr funktioniert.

Schreib vor jedem %c bei scanf ein Leerzeichen (auch bei dem hinter dem 
do).
Vor dem %lf braucht es nicht stehen, da %f automatisch Whitespace 
überliest.

von Dirk B. (dirkb2)


Lesenswert?

Theor schrieb:
> Als Lehrer würde ich das, ohne eine Erklärung, wie sich das aus der
> Spezifikation und Implementierung von scanf ergibt, um eine Note
> abwerten.


In den Beschreibung zu scanf steht sehr wohl, dass jede Art von 
Whitespace im Formatstring eben diese überliest.

Es spielt keine Rolle ob da eine Leerzeichen steht oder ein \n (oder ein 
\r oder ein \t).

Theor schrieb:
> 3. Versuchen, das Problem korrekt (wie ich meine) mit scanf/flush

fflush auf stdin ist nicht vom Standard gedeckt.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Dirk B. schrieb:
> Theor schrieb:
>> 3. Versuchen, das Problem korrekt (wie ich meine) mit scanf/flush
>
> fflush auf stdin ist nicht vom Standard gedeckt.

Macht bei Input-Streams auch eigentlich wenig Sinn.

Ich würde sowas machen wie:
1
while (getchar() != '\n')
2
    ;
Dann hab ich alles, was in der Zeile noch vielleicht so rumstand, 
verworfen, egal ob whitspace oder nicht, und ich kann in der nächsten 
Zeile sauber neu aufsetzen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Warum nicht so:
1
#define MAX_LINE_LEN     64 // oder andere Länge
2
    ...
3
    char buf[MAX_LINE_LEN];
4
5
    if (fgets (buf, MAX_LINE_LEN, stdin))
6
    {
7
        // Verarbeitung
8
    }
9
    else // EOF
10
    {
11
        // Programm beenden
12
    }

Wenn man das Ganze in eine hübsche Funktion verpacken will, dann sollte 
man dafür sorgen, dass der Buffer die Lebenszeit des Aufrufes überlebt 
(Stichwort: static).

(s)scanf() kann eine sinnvolle Funktion zum Parsen von Dateien oder 
anderen Datenquellen sein. Für das Lesen von stdin ist sie weniger 
geeignet.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.