sich gegen Eingabefehler schützen

  • C++

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von Bartosz.

    sich gegen Eingabefehler schützen

    Moin, ihr erinnert euch vielleicht noch an mein C++ Motorprojekt.
    Es ist so, dass der Nutzer eine 0 oder 1 für die Laufrichtung des Motors eingibt. Ich habe hier 2 Probleme:

    1.) Ich kenne keinen C++-Befehl für eine Funktion, die solch einen Wert zurückgibt, der auf einen Fehler schließen lässt. Ich musste leider

    C-Quellcode

    1. int dummy = scanf("%d", &Richt);
    hernehmen; und falls dummy == 0 ist 'was schiefgelaufen.

    2.) Irgendetwas scheint da nicht aktualisiert zu werden, weil wenn ein Durchlauf erfolgreich war und der Benutzer nun erneut die Richtung eingeben soll und ich ,,,,, eingebe, bleibt Richt auf 0 (statt -1), obwohl in der Funktion Richtung() -1 returnt wurde.

    hier der gesamte Code:

    im Main

    C-Quellcode

    1. while (aktiv)
    2. {
    3. Motor1.Richtung();
    4. Motor1.Eingabe_und_Berechnung();
    5. Motor1.verfahren(Motor1.Schritte);
    6. Motor1.Bewertung(Motor1.hat_geklappt);
    7. aktiv = check_ob_beenden();
    8. }


    Motor.h

    C-Quellcode

    1. #ifndef MOTOR_H_
    2. #define MOTOR_H_
    3. class Motor
    4. {
    5. private:
    6. int Richt = -1;
    7. double dFahrstrecke = 0.0;
    8. double d_mm_pro_Umdrehungen = 2.0;
    9. double d_Schritte_pro_Umdrehung = 800.0;
    10. public:
    11. int Richtung();
    12. int Eingabe_und_Berechnung();
    13. int Schritte = 0;
    14. void verfahren(int Schritte);
    15. bool hat_geklappt = false;
    16. void Bewertung(bool Bewert);
    17. };
    18. #endif // !MOTOR_H_


    motor.cpp

    C-Quellcode

    1. #include "Motor.h"
    2. #include <iostream>
    3. #include <cmath>
    4. #pragma warning(disable : 4996) //wegen scanf. Visual Studio will scanf_s sehen.
    5. int Motor::Richtung()
    6. {
    7. std::cout << "vorw\x84 \brts: 0; zur\x81 \bck: 1" << std::endl;
    8. //std::cin >> Richt;
    9. int dummy = scanf("%d", &Richt);
    10. if (dummy == 0)
    11. {
    12. std::cout << "falsche Eingabe" << std::endl;
    13. setvbuf(stdin, NULL, _IONBF, 0);
    14. setvbuf(stdin, NULL, _IONBF, BUFSIZ);
    15. return -1;
    16. }
    17. switch (Richt)
    18. {
    19. case 0:
    20. return 0;
    21. break;
    22. case 1:
    23. return 1;
    24. break;
    25. default:
    26. return -1;
    27. break;
    28. }
    29. }
    30. int Motor::Eingabe_und_Berechnung()
    31. {
    32. if (Richt == 0 || Richt == 1) //HIER
    33. {
    34. std::cout << "Fahrweg [mm] eingeben:" << std::endl;
    35. std::cin >> dFahrstrecke;
    36. if (dFahrstrecke < 0)
    37. {
    38. Schritte = 0;
    39. }
    40. else
    41. {
    42. Schritte = static_cast<int>(std::round(dFahrstrecke / d_mm_pro_Umdrehungen * d_Schritte_pro_Umdrehung)); // mm÷(mm÷U) * S÷U = S
    43. }
    44. return Schritte;
    45. }
    46. else
    47. {
    48. Schritte = 0;
    49. return Schritte;
    50. }
    51. }

    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()

    Änderung des Codes

    Ich habe meinen Code verbessert. Die Funktion int Motor::Richtung() ist nun private und wird nur durch int Motor::Eingabe_und_Berechnung() aufgerufen. Vorwärts ist nun 1 und rückwärts 2, da bei einem Lesefehler anscheinend 0 vergeben wird.

    Trotzdem wird immer noch einmal zu viel eingelesen (s. Bild).

    main

    C-Quellcode

    1. while (aktiv)
    2. {
    3. Motor1.Eingabe_und_Berechnung();
    4. Motor1.verfahren(Motor1.Schritte);
    5. Motor1.traten_Fehler_auf(Motor1.hat_geklappt);
    6. aktiv = check_ob_beenden();
    7. }


    Motor.h

    C-Quellcode

    1. #ifndef MOTOR_H_
    2. #define MOTOR_H_
    3. class Motor
    4. {
    5. private:
    6. int Richt = -1;
    7. double dFahrstrecke = 0.0;
    8. double d_mm_pro_Umdrehungen = 2.0;
    9. double d_Schritte_pro_Umdrehung = 800.0;
    10. int Richtungsbewertung = -1;
    11. int Richtung();
    12. public:
    13. int Eingabe_und_Berechnung();
    14. int Schritte = 0;
    15. void verfahren(int Schritte);
    16. bool hat_geklappt = false;
    17. void traten_Fehler_auf(bool Bewert);
    18. };
    19. #endif // !MOTOR_H_


    motor.cpp

    C-Quellcode

    1. #include "Motor.h"
    2. #include <iostream>
    3. #include <cmath>
    4. #pragma warning(disable : 4996)
    5. int Motor::Richtung()
    6. {
    7. std::cout << "vorw\x84 \brts: 1; zur\x81 \bck: 2" << std::endl;
    8. //std::cin >> Richt;
    9. int dummy = scanf("%d", &Richt);
    10. if (dummy == 0)
    11. {
    12. std::cout << "falsche Eingabe" << std::endl;
    13. setvbuf(stdin, NULL, _IONBF, 0);
    14. setvbuf(stdin, NULL, _IONBF, BUFSIZ);
    15. return -1;
    16. }
    17. setvbuf(stdin, NULL, _IONBF, 0);
    18. setvbuf(stdin, NULL, _IONBF, BUFSIZ);
    19. switch (Richt)
    20. {
    21. case 0:
    22. return -1;
    23. break;
    24. case 1:
    25. return 1;
    26. break;
    27. case 2:
    28. return 2;
    29. break;
    30. default:
    31. return -1;
    32. break;
    33. }
    34. }
    35. int Motor::Eingabe_und_Berechnung()
    36. {
    37. Richtungsbewertung = Richtung();
    38. if (Richtungsbewertung == 1 || Richtungsbewertung == 2)
    39. {
    40. std::cout << "Fahrweg [mm] eingeben:" << std::endl;
    41. std::cin >> dFahrstrecke;
    42. if (dFahrstrecke < 0)
    43. {
    44. Schritte = 0;
    45. }
    46. else
    47. {
    48. Schritte = static_cast<int>(std::round(dFahrstrecke / d_mm_pro_Umdrehungen * d_Schritte_pro_Umdrehung)); // mm÷(mm÷U) * S÷U = S
    49. }
    50. return Schritte;
    51. }
    52. else
    53. {
    54. Schritte = 0;
    55. return Schritte;
    56. }
    57. }
    Bilder
    • noch einmal zu viel.jpg

      57,66 kB, 706×707, 82 mal angesehen
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    @Bartosz Wenn Du in einer Eingabeschleife GetAsyncKeyState() verwendest, kannst Du gezielt jede einzelne Taste abfragen:
    docs.microsoft.com/en-us/windo…-winuser-getasynckeystate
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hallo @Bartosz,
    dürfte ich wissen weshalb du scanf anstelle von std::cin verwendest?

    Desweiteren kannst du dieses unnötige switch-statement mit

    C-Quellcode

    1. return (Richt == 1 || Richt == 2 ? Richt : -1);

    auswechseln.
    ----------------------------------------------------------------------------------------------------------------------

    Hier könnte meine Signatur stehen, aber die ist mir abfußen gekommen.

    ----------------------------------------------------------------------------------------------------------------------
    Hallo @Elanda

    dürfte ich wissen weshalb du scanf anstelle von std::cin verwendest?
    Weil ich kein C++-Befehl kenne, der einen Rückgabewert gibt,der auf einen Fehler schließen lässt.

    C-Quellcode

    1. return (Richt == 1 || Richt == 2 ? Richt : -1);
    Ok, danke ^^
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    Kennst Du überhaupt einen Befehl,

    Bartosz schrieb:

    der auf einen Fehler schließen lässt
    :?:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany ich meinte das so

    C-Quellcode

    1. int dummy = scanf("%d", &Richt);
    Richt ist ein int.
    • Wenn der Benutzer jetzt Müll eingibt, z.B. einen Char, dann wird auf dummy 0 geschrieben. Somit kann ich das prüfen.
    • Wenn alles richtig gelaufen ist, dann wird dummy 1.
    • Wenn mehr richtig eingelesen wird (hier nicht relevant), dann wird dummy so groß, je nachdem, wie viel eingelesen worden ist.
    Jedenfalls habe ich mir am Samstag gedacht, mit dieser Rückgabe und der do-While-Schleife aus Post 3 kann ich Müll verhindern. Der Sinn dieses Threads besteht darin, dies auf C++ zu verändern und den Doppeldurchlauf zu vermeiden.
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    Was meinst du mit "Fehler"?

    Wenn du meinst das er etwas anderes als 1 oder 2 angibt, dann kannst du wie ich es dir oben angezeigt habe, auch genau so darstellen.

    Verwende einfach std::string Variablen.
    Dann checkst du den string einfach

    C-Quellcode

    1. string == "1" || string == "2"

    und kannst so sichergehen ob es richtig oder ein "Fehler" ist.

    Wenn du mit Fehler etwas anderes gemeint hattest, musst du mir das erst erklären!

    Edit:
    Wenn der Check erfolgreich war kannst du den Zeichenkettenwert mit

    C-Quellcode

    1. std::stoi
    zu einen Ganzzahlenwert umwandeln. (wenn nötig)
    ----------------------------------------------------------------------------------------------------------------------

    Hier könnte meine Signatur stehen, aber die ist mir abfußen gekommen.

    ----------------------------------------------------------------------------------------------------------------------

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Elanda“ ()

    Wenn du meinst das er etwas anderes als 1 oder 2 angibt,
    Ja.
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.