Abfrage funktioniert nicht



  • Hi, versuche mit einem if eine Division durch 0 zu verhindern. Leider macht er sie trotzdem immer.

    #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
    
    float zahl1, zahl2;
    char op;
    
    printf("Bitte geben sie die erste zahl ein:");
    scanf("%f", &zahl1);
    
    printf("Bitte geben sie ein wie gerechnet werden soll<+,-,*>: ");
    scanf("%s", &op);
    
    printf("Bitte geben sie die zweite zahl ein:");
    scanf("%f", &zahl2);
    
    if (op == '+')
    {
        printf("Die Summe ist: %.2f \n", (zahl1 + zahl2));
    }
    else if (op == '-')
    {
        printf("Die Summe ist: %.2f\n", (zahl1 - zahl2));
    }
    else if (op == '*')
    {
        printf("Die Summe ist: %.2f\n", (zahl1 * zahl2));
    }
    else if (op == '/')
    {
        if (zahl2 == '0')
        {
            printf("Divident ist 0");
    
        }
        else
            printf("Die Summe ist: %.2f\n", (zahl1 / zahl2));
    }
    return 0;
    
    }
    


  • #include <stdio.h>
    #include <string.h>
    
    int main(void)
    {
    
    float zahl1, zahl2;
    char op;
    
    printf("Bitte geben sie die erste zahl ein:");
    scanf("%f", &zahl1);
    
    printf("Bitte geben sie ein wie gerechnet werden soll<+,-,*>: ");
    scanf("%s", &op); /* undefiniertes Verhalten, du schreibst in Speicher, der dir nicht gehört */
    
    printf("Bitte geben sie die zweite zahl ein:");
    scanf("%f", &zahl2);
    
    if (op == '+')
    {
        printf("Die Summe ist: %.2f \n", (zahl1 + zahl2));
    }
    else if (op == '-')
    {
        printf("Die Summe ist: %.2f\n", (zahl1 - zahl2));
    }
    else if (op == '*')
    {
        printf("Die Summe ist: %.2f\n", (zahl1 * zahl2));
    }
    else if (op == '/')
    {
        if (zahl2 == '0')  /* Unsinn: Vergleich von float mit char */
        {
            printf("Divident ist 0"); /* Dividend */
    
        }
        else
            printf("Die Summe ist: %.2f\n", (zahl1 / zahl2));
    }
    return 0;
    
    }
    

    Besser du liest die floats zunächst mal als string (char[]) ein, und wandelst dann erst bei Berechnungen nach float (z.B. mit atof).
    Dann ist der Vergleich mit Strings auf 0 sicherer als der mit floats.


  • Mod

    Wutz schrieb:

    Besser du liest die floats zunächst mal als string (char[]) ein, und wandelst dann erst bei Berechnungen nach float (z.B. mit atof).
    Dann ist der Vergleich mit Strings auf 0 sicherer als der mit floats.

    Das klingt mystisch. So etwas von dir? Da fallen mir spontan zig Schreibweisen für 0 ein, die von scanf alle als 0 aufgefasst werden (und auch beim Vergleich als 0 gelten, als was sonst?), aber ich wette, du denkst nicht an alle beim Stringvergleich.



  • okay danke. Liegt an den Datentypen. Werde das schon hinkriegen. Habe aber ein weit größeres Problem unter Windows 7.

    Wenn ich das Programm im cmd kompliere dann hab ich keine Probleme mit der Eingabe.

    Unter Windows und Eclipse gibt er kein printf aus. fscanf funktioniert trotzdem. Muss blind meine Eingaben machen und zum Schluss gibt er die Befehle mit allen printf zusammen aus.



  • printf("Bitte geben sie ein wie gerechnet werden soll<+,-,*>: ");
    scanf(" %c", &op); 
    //     ^ Das Leerzeich vor dem % ist auch wichtig.
    

    Es ist in C ein großer Unterschied zwischen 0 , '0' und "0" .



  • Mit
    [code="c"]fflush( stdout );[/code="c"]
    vor jedem printf gehts. Gibst da praktischere Lösungen ?

    Der Cursor steht auch auf der falschen Stelle bevor man eine Eingabe tätigt.



  • Das ist ein Fehler von Eclipse bzw der Shell von Eclipse.



  • Bei float sind Abfragen auf Gleichheit ohnehin sehr gefährlich, weil selten exakt.
    Ausweg Abfrage mit Absolutwert und Toleranz:

    float eps = 0.00001;
    if(Math.Abs(zahl) < eps)   /* Gleichheit */
    

  • Mod

    Aber doch nicht, wenn wir auf 0 prüfen wollen, um Division durch Null* zu verhindern! 0 ist 0! Und selbst etwas Kleines, wie 1e-632, ist bezüglich der Division ungleich 0. Und bevor jemand fragt: Auch -0, +0 und ähnliches ist gleich zu 0.
    Die Technik mit dem epsilon-Vergleich ist ebenfalls nicht der Weisheit letzter Schluss. Oftmals will man relative Vergleiche. Oder eine Mischung aus beidem.

    *: Was ist da dran eigentlich abfangwürdig? Das Ergebnis ist eben inf, -inf oder nan, je nach dem, was der Dividend ist. Apropos Dividend: Angenommen a/b. a nennt man "Dividend", b "Divisor". Das ist im Programm falsch. Abgesehen davon ist alles eine "Summe". Das kommt davon, wenn man mit Copy&Paste programmiert.



  • float eps = 0.00001;
    if(Math.Abs(zahl < eps))   /* Gleichheit */
    

    Nicht Gleichheit sondern falsch.

    http://ideone.com/ezIFUp
    macht es ohne Gleichheitsoperatoren



  • Wutz schrieb:

    [code="c"]
    printf("Bitte geben sie ein wie gerechnet werden soll<+,-,>: ");
    scanf("%s", &op); /
    undefiniertes Verhalten, du schreibst in Speicher, der dir nicht gehört */

    mit %c für funktioniert es aber leider nicht. Warum auch immer :(. Würde sich als einzelnes Zeichen super anbieten.


  • Mod

    TE_Guest schrieb:

    mit %c für funktioniert es aber leider nicht. Warum auch immer :(.

    Das könnte an dir sicherlich sagen, wenn du nur richtig fragen würdest. So mit Code und Fehlerbeschreibung. Den Beitrag von DirkB hast du doch gelesen, oder?
    http://www.c-plusplus.net/forum/p2351260#2351260



  • "&op" heißt Adresse auf (ein) char, "%s" weist scanf aber an, immer mind. 2 Zeichen zu schreiben (terminierende '\0'), op ist bei dir aber wie gesagt nur 1 Byte groß.



  • SeppJ schrieb:

    aber ich wette, du denkst nicht an alle beim Stringvergleich.

    Ich wette nie. Mehr als 1 führende 0 mal ausgeschlossen:
    http://ideone.com/m5iXKP
    Hat auch den Vorteil, dass hier die "Genauigkeit" für 0 explizit gesetzt werden kann, bei der float-Rumrechnerei bist du immer implementierungsabhängig.



  • aha 🙂

    sry das von Dirk hab ich fast übersehen das das von Bedeutung ist. Mit

    scanf(" %c", &op);
    

    klappt es auch.

    Wenn ich es richtig verstanden von euch dann speichert ein %s ( String ) immer mindestens 2 Byte. Deswegen hat das bei mir auch funktioniert auch wenn man es so nicht realisieren sollte.

    Char speichert nur 1 Byte... mit dem Terminierungsoperator '\0' brauch ich dann mindestens 2 Zeichen ? Deswegen

    " %c"

    um 2 Zeichen zu speichern ? Hab ich das richtig verstanden.


  • Mod

    Wutz schrieb:

    Hat auch den Vorteil, dass hier die "Genauigkeit" für 0 explizit gesetzt werden kann, bei der float-Rumrechnerei bist du immer implementierungsabhängig.

    Aber Genauigkeit ist hier doch gar nicht gefragt! Exakt 0 ist gefragt. Und da ist der Stringvergleich einfach nur falsch. 0.0000000000000001 ist eben nicht 0! Selbst wenn du Werte unter einem gewissen Wert als 0 ansiehst: "123e-37" ist eine übliche Angabe, mit der scanf wunderbar umgehen könnte und hinterher könnte man da je nach Bedarf absolut, relativ oder mit epsilon vergleichen. Stringvergleich scheitert.
    Ich sehe jede Menge Nachteile, keinen einzigen Vorteil. Die angepriesenen Vorteile werden von dieser Lösung sogar ausdrücklich nicht erfüllt.



  • SeppJ schrieb:

    *: Was ist da dran eigentlich abfangwürdig? Das Ergebnis ist eben inf, -inf oder nan, je nach dem, was der Dividend ist.

    Bzw. undefiniertes Verhalten, wenn wir ausnahmensweise mal nach dem Standard gehen.



  • TE_Guest schrieb:

    Wenn ich es richtig verstanden von euch dann speichert ein %s ( String ) immer mindestens 2 Byte. Deswegen hat das bei mir auch funktioniert auch wenn man es so nicht realisieren sollte.

    Char speichert nur 1 Byte... mit dem Terminierungsoperator '\0' brauch ich dann mindestens 2 Zeichen ? Deswegen

    " %c"

    um 2 Zeichen zu speichern ? Hab ich das richtig verstanden.

    Nein absolut nicht.
    Bei dir hat das nur durch Zufall funktioniert. Du hattest nur Platz für ein Zeichen reserviert (deine Variable op). Die '\0' wurde also in Speicher geschrieben, der nicht dafür vorgesehen war. (buffer overflow)

    Das Leerzeichen vor dem % bewirkt, dass scanf alle Whitespace überliest.
    Der Grund dafür ist, das scanf nur die Zeichen aus dem Eingabestrom einliest, die es auch zur Verarbeitung des aktuellen Formates braucht.
    Die Eingabetaste, die du nach der Eingabe von zahl1 betätigt hast, gehört nicht zu einer Fließkommazahl. Darum bleibt das Zeichen für die Eingabetaste ('\n') stehen.
    Normalerweise überliest scanf Whitspace bei den meisten Formaten. Allerdings nicht bei %c. (Du könntest ja gerade dieses Zeichen haben wollen)

    scanf ist sehr komplex und daher nicht ganz einfach zu durchschauen.
    Lies dir eine Referenz zu scanf durch. Z.B. http://www.cplusplus.com/reference/cstdio/scanf/



  • Danke für die Erklärung aber etwas verwirrt bin ich.

    Ein char ist ein Zeichen das ein Byte lang ist. Der Terminierungsoperator ist aber schon mal 1 Byte groß. Wie passt das zusammen ? Ist jeder char 2 Byte lang ?

    Die Erklärung war gut. Bis auf diesen Satz hab ich es verstanden.

    Darum bleibt das Zeichen für die Eingabetaste ('\n') stehen.



  • Die Nullterminierung ist eine Vereinbarung um Zeichenketten in C verarbeiten zu können.
    Damit wird das Ende einer Zeichenkette markiert. Das sagt nichts darüber aus, wieviel Platz da noch vorhanden ist.

    Für einzelne Zeichen wird die nicht gebraucht, denn du hast ja nur ein Zeichen.

    Dadurch, dass du für Zeichenketten Arrays hast, ist der Unterschied schon deutlich.

    Das Zeichen für die Eingabetaste ist '\n' (NewLine).
    In C kann man (zumindest ein) Zeichen in den Eingabestrom zurückstellen, wenn man es nicht für die Eingabe benötigt.
    Beispiel Integerzahl. Wenn scanf etwas anderes als Ziffern einliest, dann ist die Eingabe fertig. Allerdings wurde dieses andere Zeichen ja schon eingelesen. scanf stellt es darum wieder in den Eingabestrom zurück, damit es für die nächste Eingabe zur Verfügung steht) (siehe die Funktion ungetc )


Anmelden zum Antworten