mikrocontroller.net

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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Sascha (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: René H. (Firma: Herr) (hb9frh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
getline() statt scanf()

Grüsse,
René

Autor: Theor (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sascha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include <stdio.h>
#include <math.h>

int main(){
    char c;
    int i;
    double A[10];
    
    do{
        printf("Summe[+] oder Produkt[*]?\n");
        scanf("%c", &c);
        /**getchar();**/
        printf("Startwert Eingeben:\n");
        scanf(" %lf", &A[0]);
        if(A[0] == 0){
            printf("Startwert darf nicht Null sein");
        }
            else{
                switch(c){
                case '+':
                    for(i=1;i<=10;i++){
                    A[i] = A[i-1] + A[0];
                    printf("%lf\n", A[i-1]);
                    }
                    break;
                case '*':
                    for(i=1;i<=10;i++){
                    A[i] = A[i-1] * A[0];
                    printf("%lf\n", A[i-1]);
                    }
                    break;
                default: 
                printf("Sie waren zu dumm, die erste Eingabe zu verstehen. Bitte fahren Sie das System herunter und benutzen Sie nie wieder einen PC\n");
                }
            }
        printf("Moechten Sie beenden?\n");
        /**getchar();**/
        scanf(" %c", &c);
        getchar();
    }while(c != 'j');
    }
    

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 Moderator
Autor: Theor (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
Autor: Dirk B. (dirkb2)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Dirk B. (dirkb2)
Datum:

Bewertung
0 lesenswert
nicht 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
Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht 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:
while (getchar() != '\n')
    ;
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.

Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum nicht so:
#define MAX_LINE_LEN     64 // oder andere Länge
    ...
    char buf[MAX_LINE_LEN];

    if (fgets (buf, MAX_LINE_LEN, stdin))
    {
        // Verarbeitung
    }
    else // EOF
    {
        // Programm beenden
    }

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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.