Forum: Compiler & IDEs Problem mit scanf


von Max (Gast)


Lesenswert?

Hallo,

ich bin gerade dabei, in WinAVR mit der scanf Funktion
herumzuexperimentieren mit folgendem Code in der main loop (mit
fdevopen wurden printf und scanf auf den UART gelenkt):

int iTestvar;
while(1)
{
   scanf("%d", iTestvar);
   printf("%d\n\r", iTestvar);
}

Eine per Hyperterminal eingegebene Dezimalzahl soll also wieder zurück
ans Hyperterminal gesendet werden. Das funktioniert mit Dezimalzahlen
auch prima, sobald ich allerdings ein ungültiges Zeichen wie z.B. 'g'
eintippe, dann wird ständig die ASCII-Ziffer '0' ans Hyperterminal
gesendet. Soweit ich weiss, bricht scanf bei einem ungültigen Zeichen
ab, soweit ok, aber warum wird dann beim nächsten scanf nicht wieder
gewartet, bis ein Zeichen vorhanden ist?

cu,
Max

von Jörg Wunsch (Gast)


Lesenswert?

Weil es per Standard an der Stelle aufhören muss zu scannen, an der es
einen Konvertierungsfehler gab.  Wenn du nun an der gleichen Stelle
weitermachst, gibt's natürlich wieder den gleichen
Konvertierungsfehler.  Du solltest einfach die Fehlerauswertung
durchführen.

von Rufus T. Firefly (Gast)


Lesenswert?

scanf("%d", iTestvar);


Das geht nicht bzw. wird interessante Auswirkungen haben.
Aufgrund des Formatstringes erwartet scanf nämlich einen Pointer auf
int. Was Du aber übergibst ist ein int. Der wird wie ein Pointer
behandelt, und je nachdem, welchen Wert der int hat, wird also
irgendwo in den Speicher geschrieben.

   scanf("%d", &iTestvar);

sollte sinnvollere Resultate liefern.

von Max (Gast)


Lesenswert?

Danke für die Antworten.

Den Adressoperator & vor iTestvar bei scanf habe ich verwendet, das war
ein Tippfehler beim Schreiben des Beitrags. Ohne & würde das ja auch mit
gültigen Dezimalzahlen nicht funktionieren.

Wie funktioniert das mit der Fehlerauswertung genau? Als Rückgabewert
wird doch die Anzahl der eingelesenen Zeichen zurückgeliefert, richtig?
Woher "weiß" scanf beim nächsten Aufruf, dass zuvor ein fehlerhaftes
Zeichen eingegeben wurde?

cu,
max

von michaelr (Gast)


Lesenswert?

hallo ! aus langjähriger erfahrung mit scanf: ich würde einen bogen drum
machen, wenn es irgendwie geht. auch in windows-software verzichte ich
lieber drauf, auch wenn es bei float variablen so verlockend ist. ist
übrigens nicht nur meine meinung. michael

von Rufus T. Firefly (Gast)


Lesenswert?

Das Problem liegt hier daran, daß scanf den Eingabepuffer nicht löscht.

Sinnvoller als scanf ist meines Erachtens nach die Kombination aus gets
(was eine komplette Zeile einliest) und sscanf. Vor dem Aufruf von
sscanf kann eine einfache Plausibilitätsprüfung erfolgen (wurden
überhaupt genügend Zeichen eingegeben?).

Wenn es nur darum geht, einen numerischen Wert einzulesen, ist gets in
Kombination mit atoi/atof sicherlich eine zuverlässigere Lösung.

von Jörg Wunsch (Gast)


Lesenswert?

Ich würde auch fgets + sscanf bevorzugen (nicht gets, weil man da
keine Kontrolle hat, dass der Nutzer den Puffer nicht überlaufen
lassen kann).

Ansonsten: jede beliebige Beschreibung von scanf in einem beliebigen
C-Buch lesen.  scanf gibt die Anzahl der durchgeführten
Konvertierungen zurück, im obigen Fehlerfalle also wohl eine 0.

von Stefan F. (sfrings)


Lesenswert?

Ich möchte nochmal auf den ürsprünglichen Code zurück kommen, weil das 
Thema noch nicht so ganz verstanden habe. Mein mißratener Code sieht so 
aus:

int number;

int main(void) {
    // initialize the serial port
    initserial();
    // switch LED on
    DDRB |= (1<<PB2);
    PORTB &= ~(1<<PB2);
    // mail loop
    while (1) {
        printf("Enter a number\r\n");
        scanf("%d",&number);
        printf("You entered: %d\r\n",number);
    }
}

Problem 1:
Sobald ich einen Buchstaben eingebe, scheint das Programm abzustürzen 
und sich selbst zu zerstören. Denn nach Strom aus und wieder an geht 
nichtmal die LED an. Ich muss dann den Controller neu flashen. Und das 
passiert immer, 100% reproduzierbar.  Was ist denn hier falsch?

Problem 2:
Wenn ich die Deklaration der Variable "number" in die main Methode 
hinein verschiebe, wartet scanf nicht auf meine Eingabe, sondern die 
Schleife wiedeholt sich endlos und gibt irgendeine negative Zahl aus. 
Ich tippe jetzt mal auf Stack Fehler, bin mir mir aber nicht im Klaren, 
wodurch ich den produziert haben könnte. Die Zeilen von initserial() und 
den Funktionen zum senden und empfangen habe ich nämlich 1:1 der 
glibc-Doku entnommen.

Problem 3:
Wenn scanf im Fehlerfall den Eingabepuffer nicht leert, wie kann ich das 
dann "manuell" tun?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Stefan Frings wrote:
> Ich möchte nochmal auf den ürsprünglichen Code zurück kommen, ...

Nein, bitte nicht nach 4 Jahren.  Bitte mach einen neuen Thread auf.
Auch wenn das Problem gleich klingt, ist es meistens was komplett
anderes.

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.