mikrocontroller.net

Forum: Compiler & IDEs Problem mit scanf


Autor: Max (Gast)
Datum:

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

Autor: Jörg Wunsch (Gast)
Datum:

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

Autor: Rufus T. Firefly (Gast)
Datum:

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

Autor: Max (Gast)
Datum:

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

Autor: michaelr (Gast)
Datum:

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

Autor: Rufus T. Firefly (Gast)
Datum:

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

Autor: Jörg Wunsch (Gast)
Datum:

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

Autor: Stefan Frings (sfrings)
Datum:

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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

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

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.