C problem mit scanf und "Enter"

Gast #5434061
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
Gast #5434073
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.
Gast #5434076
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.
Gast #5434087
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 von einem Moderator gelöscht.
#5434307
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.
#5434311
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.
#5434755
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.
Moderator Persönliche Seite #5434785
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.

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