Problem mit scanf Übergabeparamenter



  • gets soll man nicht verwenden, das ist auch gut so.
    Du wertest den Rückgabewert von scanf nicht aus, ist ebenso schlecht.

    int liesLong(long *l)
    {
      char s[100],*e;
      errno=0;
      fgets( s,100,stdin );
      *l=strtol( s,&e,10 );
      return (!*e||*e=='\n')&&errno!=ERANGE;
    }
    
    long l;
    if( liesLong(&l) )
      printf("%ld",l);
    else
      fputs("Fehler",stderr);
    

    Akzeptiert werden hierbei außer Ziffern nur führende Whitespaces in der Nutzereingabe.



  • Ok, danke euch erstmal für eure Antworten. Hab schon ein bisschen rumgebastelt.

    DirkB schrieb:

    In diesem Fall steht in auswahl noch ein Wert drin, den du als Fehler auffasst.
    Mach doch mal

    auswahl = 1;
    scanf("%d",&auswahl);
    printf("Ihre Wahl: %d\n", auswahl);
    

    und gib das w ein.

    Hm, also dass hat leider nicht funktioniert. Wenn man nur w eingibt schon, aber das war vorher ja auch schon der Fall. Wenn man jedoch 1w eingibt wird trotzdem der Menüpunkt 1 ausgeführt.

    Wutz schrieb:

    gets soll man nicht verwenden, das ist auch gut so.
    Du wertest den Rückgabewert von scanf nicht aus, ist ebenso schlecht.

    int liesLong(long *l)
    {
      char s[100],*e;
      errno=0;
      fgets( s,100,stdin );
      *l=strtol( s,&e,10 );
      return (!*e||*e=='\n')&&errno!=ERANGE;
    }
    
    long l;
    if( liesLong(&l) )
      printf("%ld",l);
    else
      fputs("Fehler",stderr);
    

    Akzeptiert werden hierbei außer Ziffern nur führende Whitespaces in der Nutzereingabe.

    Ok danke, das hat schon funktioniert. Allerdings versteh ich den Code nicht so ganz. Könntest du mir vielleicht bitte die return Zeile aus deiner liesLong Funktion erklären, die kapier ich mal gar nicht. Und wofür brauchst du ein char-Array der Größe 100?



  • Lies dir die Spezifikation von strtol gründlich durch, und du solltest das return verstehen.
    Lies dir die Spezifikation von fgets gründlich durch, und du solltest s verstehen.



  • @Wutz
    Ich finde deine Listings klasse, aber ihn so zappeln zu lassen ist schon a bissl fies 😉

    @eey
    Kannst normal von links nach rechts lesen, es wird der Wahrheitsgehalt (boolscher Wert) gegen 0 getestet.
    (!*e || *e=='\n') && errno != ERANGE
    ('0' ODER 'CR + LF') UND errno UNGLEICH ERANGE

    Gruß



  • forenseeker schrieb:

    @Wutz
    Ich finde deine Listings klasse, aber ihn so zappeln zu lassen ist schon a bissl fies 😉

    @eey
    Kannst normal von links nach rechts lesen, es wird der Wahrheitsgehalt (boolscher Wert) gegen 0 getestet.
    (!*e || *e=='\n') && errno != ERANGE
    ('0' ODER 'CR + LF') UND errno UNGLEICH ERANGE

    Gruß

    Hm danke, aber ich verstehs leider immer noch nicht so ganz.... Was bedeutet !*e, soll das "nicht pointer auf e" heißen? Die boolsche Verknüpfung hab ich kapiert aber WAS wird dann zurückgegeben? Eine 1 falls e ungleich der NULL Pointer oder \n ist sowie kein Fehler auftritt? Und ansonsten eine 0?

    Wutz schrieb:

    Lies dir die Spezifikation von strtol gründlich durch, und du solltest das return verstehen.
    Lies dir die Spezifikation von fgets gründlich durch, und du solltest s verstehen.

    Hab ich gemacht, jedoch ist mir immer noch nicht klar warum dass Array 100 groß sein muss (muss es meiner Meinung nach nämlich nicht)? Schließlich wird so ein Menü ja maximal ne zweistellige Anzahl an Menüpunkten aufweisen, damit wäre ja für eine 100-stellige Anzahl an Menüpunkten Speicherplatz reserviert, was ja etwas übertrieben ist. Oder welchen anderen Grund soll das haben?

    Auch das return verstehe ich leider noch nicht ganz, strtol hab ich schon kapiert: Die Funktion interpretiert den String s als Dezimalzahl (wegen dem 10er) und speichert ihn in e. Im Erfolgsfall wird die interpretierte Zahl als long int zurückgegeben, ansonsten 0. Aber was genau hat das jetzt dem hier verwendeten return zu tun, ich seh da keinen Zusammenhang...?

    Hab auch nebenher noch eine andere Frage, gibt es eine Möglichkeit eine Tastatureingabe DIREKT zu übernehmen? Also ohne erst mit Enter bestätigen zu müssen?



  • eey schrieb:

    Auch das return verstehe ich leider noch nicht ganz, strtol hab ich schon kapiert: Die Funktion interpretiert den String s als Dezimalzahl (wegen dem 10er) und speichert ihn in e. Im Erfolgsfall wird die interpretierte Zahl als long int zurückgegeben, ansonsten 0. Aber was genau hat das jetzt dem hier verwendeten return zu tun, ich seh da keinen Zusammenhang...?

    Und außerdem liefert strtol() einen Zeiger auf das erste Zeichen zurück, das nicht interpretiert werden konnte. Des weiteren ist der Ausdruck !*e äquivalent zu *e=='\0' - das heißt die Abfrage stellt sicher, daß hinter der interpretierten Eingabe das String-Ende oder der Zeilenumbruch steht (und fängt damit Eingaben wie "5ab" ab).

    Hab auch nebenher noch eine andere Frage, gibt es eine Möglichkeit eine Tastatureingabe DIREKT zu übernehmen? Also ohne erst mit Enter bestätigen zu müssen?

    Mit Standard-Mitteln geht das afaik nicht, da bist du auf den Tastaturtreiber angewiesen, der die Eingaben zeilenweise übergibt. Aber es gibt auch systemspezifische Funktionen, die die Eingaben direkt holen, z.B. kbhit() + getch()

    Edit: Es ist schon erstaunlich, daß Google unseren FAQ-Beitrag als erstes Suchergebnis für "kbhit" liefert.



  • @eey

    Falls der wutzige Return-Wert noch Probleme macht:
    (!*e || *e=='\n') && errno != ERANGE

    !*e heisst nicht "Nicht Pointer", sondern besagt das der nachfolgende Wert nicht >0 sein darf um wahr zu sein. Es wird auf den Wert in e referenziert nicht auf die Adresse. Z.B.:

    if (*e) // der Klammerasudruck ist wahr, wenn Wert in e > 0
    if (!*e) // der Klammerausdruck ist wahr, wenn Wert in e == 0 (oder e nicht größer Null oder e < kleinster darstellbarer Wert, oder nicht definiert. Wie man will).

    Der Klammerausdruck (!*e || *e=='\n') wird somit wahr, wenn in *e ein Wert größer 0 steht oder 'CR/LF'. Wurde bis jetzt fehlerfrei umgewandelt ist der Klammerausdruck 0.

    Dann kommt die zweite Bedindung && errno!=Erange :
    Wenn beim Umwandeln der Wertebereich für long verlassen wurde ist dies als Fehler zu sehen und somit 1, damit wird automatisch der gesamte Ausdruck 1. Was für den Returnwert heisst, das ein Fehler auftrat.

    Ist der Klammerausdruck 1 wird die logische Operation && nicht ausgeführt da schon der Gesamtausdruck, ob 0 oder 1, feststeht.

    ist gar kein Fehler aufgetreten bleiben beide Ausdrücke 0.

    Ich hoffe dir wurde gehelft 😃

    Frage an die Profis:

    "Müsste es im Klammerausdruck nicht **e=='\n' heissen? Also Doppelpointer auf den referenzierten Wert aus e? Sonst ist der Teil nach || immer wahr wenn !*e erfüllt wurde und die Abfrage somit sinnlos?

    Oh Gott, oh Gott! Mir dreht sich alles 😮



  • Nenenenene, so nich:

    if (*e) // *e != 0 denn 0 ist unwahr und !0 ist wahr. Nix mit >

    '\n' ist nur ein Newline (auch Lindfeed genannt) also LF
    '\r' ist das Carriage Return also CR

    Und e ist vom Typ char*
    Daher ist auch nur ein * ausreichend

    forenseeker schrieb:

    ist gar kein Fehler aufgetreten bleiben beide Ausdrücke 0.

    Genau anders herum: 1 bedeutet ergolgreich. Schau dir den Aufruf an 🙂



  • DirkB schrieb:

    Nenenenene, so nich:

    if (*e) // *e != 0 denn 0 ist unwahr und !0 ist wahr. Nix mit >

    '\n' ist nur ein Newline (auch Lindfeed genannt) also LF
    '\r' ist das Carriage Return also CR

    Und e ist vom Typ char*
    Daher ist auch nur ein * ausreichend

    forenseeker schrieb:

    ist gar kein Fehler aufgetreten bleiben beide Ausdrücke 0.

    Genau anders herum: 1 bedeutet ergolgreich. Schau dir den Aufruf an 🙂

    😞 irgendwie ist mir jetzt schwindelig.

    ich sage doch auch:
    if (*e) // ist erfüllt wenn der Wert !0 bzw. eben >0 ist. (// kommentarzeichen nicht "oder") oder von mir aus auch kleiner 0 bei signed und nicht bei pointern

    Bei Linux ist 'n' = newline, korrekt und bei Windows ist es Lf + CR, womit ich mich als Windows User oute.

    Ich denke der Returnwert ist nur dann nicht Null wenn ein Fehler auftritt.

    In der Funktionsbeschreibung zu strtol stand
    strtol(const char *s, char **endp, int base)
    daher meine Frage.

    Help please



  • forenseeker schrieb:

    if (*e) // ist erfüllt wenn der Wert !0 bzw. eben >0 ist. (// kommentarzeichen nicht "oder") oder von mir aus auch kleiner 0 bei signed und nicht bei pointern

    Du kennst den Unterschied zwischen ">" und "!=" ?

    Bei Linux ist 'n' = newline, korrekt und bei Windows ist es Lf + CR, womit ich mich als Windows User oute.

    Und um die Auflistung zu vervollständigen, beim MAC gibt es nur CR als Zeilenende-Kennzeichen. Aber die Funktionen der <stdio.h> kümmern sich darum, daß du von diesem Unterschieden normalerweise nichts mitbekommst.



  • CStoll schrieb:

    Du kennst den Unterschied zwischen ">" und "!=" ?

    Ja, danke. Ich hätte es geschickter formulieren sollen.

    Gruß


Anmelden zum Antworten