Ausnahmebehandlung für eine string Funktion



  • Hi, Mümmelchen. Leider geh ich aus sehr bösen Angewohnheit davon aus das ich verstanden werde. Ich wollte nur allgemein wissen ob mein Ansatz richtig war.
    Wie du schon richtig erkannt hast, es gab davor ein Programm mit dieser Funktion:

    int main()
    {
    //Funktion vom Typ string namens nick( nickname)
    string nick("\ncapitalQ"); 
    cout << nick <<endl;
    
    return 0;
    
    }
    

    Jetzt muss laut Aufgabenstellung folgendes passieren:

    Überarbeiten Sie das Programm so, dass es mittels C++ Ausnahmen mögliche Fehler erkennt. Nach dem Abfangen eines Fehlers soll das Programm eine vernünftige Fehlermeldung ausgeben und sich beenden.

    PS: noch Mal sorry für meine Sturrheit und Unklarheiten 😉



  • Hi Helenchen,

    formatiere das Musterbeispiel aus Deinem Script ordentlich um, so wie ich es Dir gezeigt habe, auch mit einer Leerzeile zwischen der Div-Funktion und Main und dann siehst Du es alleine, dann wird es Dir (hoffentlich) wie Schuppen aus den Haaren fallen.

    In dem Beispiel ist alles wesentliche und benötigte enthalten und Du brauchst es nur noch passend zu verwenden.

    Was in Deiner Antwort immer noch fehlt ist die nick-Funktion. Wie soll sie aussehen, wie soll da eine Exception nötig werden? Wie sie geworfen wird beschreibt ja das Musterbeispiel schon passend.

    Bis denne
    Gruß Mümmel



  • muemmel schrieb:

    Hi Helenchen,

    formatiere das Musterbeispiel aus Deinem Script ordentlich um, so wie ich es Dir gezeigt habe, auch mit einer Leerzeile zwischen der Div-Funktion und Main und dann siehst Du es alleine, dann wird es Dir (hoffentlich) wie Schuppen aus den Haaren fallen.

    habe ich gerade erkannt.

    In dem Beispiel ist alles wesentliche und benötigte enthalten und Du brauchst es nur noch passend zu verwenden.

    Genau das ist mein Problem
    die if abfrage nach was in meinen Fall?
    habe nach "nicht string" versucht, aber irgendwie gefehlt mir diese Schreibweise nicht

    #include <iostream>
    #include<stdexcept>
    using namespace std;
    
     // Definition einer Variablen vom Typ std::string namens nick (nickname):
       string nick (string nickname){
       if( nickname != "") // wenn string nicht string => wie macht man es richtig ?
       throw runtime_error{ "nick(), nicht string"};
       return nickname;
       }
    int main() {
        try{
    
        nick("\ncapitalQ"); 
    
       return 0;
    
        }
    
    catch ( const runtime_error& re ) {
    
    cerr << "Caught: " << re.what( ) << endl;
    
    return -1;
    
      }
    }
    

    Wie soll sie aussehen, wie soll da eine Exception nötig werden?

    Gute Frage. Proff gibt keine genauen Hinweise darauf 😕 😞



  • Du scheinst das absolute Minimum deiner Zeit in die vernünftige wiedergabe deines Problems zu investieren, womit du es Anderen nicht gerade leicht machst dir zu helfen.

    Das richtige Formulieren eines Problems ist der erste Schritt zur Lösung. Um so früher du das begreifst, um so besser wirst du in deinem vermutlichen MINT Studium voran kommen.

    Am besten fängst du damit gleich Hier an! Versuche wie Muemmel schon sagte, deinen Quellcode (und deinen Text!) lesbar zu formatieren. Falls du nicht weißt was damit gemeint ist, google es (z.B.: "Wie formatiert man C++ Code richtig"). Anschließend versuche deine Frage mit allen nötigen Informationen zu ergänzen, angefangen mit der Aufgabenstellung vom Professor!



  • Hi Helenchen,

    normalerweise gleich erst mal 3 rechts 3 links (Ohrfeigen), weil das was Du mir da zurückgeschrieben hast immer noch nicht richtig formatiert ist.
    Wer soll es denne in Form bringen wenn nicht Du.
    Nicht String ist schon erst mal falsch, denn auch der leere String ist ein String. Es sei den, du gibst gleich NULL rüber, das wäre dann wohl wirklich kein String.
    Aber guck Dir noch mal Deinen übergebenen String an. "\ncapitalQ" ist wohl kein passender String. Wie willst Du jeweils einen NIckname eingeben, der mit \n beginnt.
    Also teste, vom ersten bis zum letzten Zeichen, ob der Wert außerhalb a-z und außerhalb A-Z liegt. (Als Sahnehäubchen kannst Du ja noch auf Umlaute und ß testen). Ists keines von all denen dann wirf ne Exception.
    Und dann ne vernünftige Fehlermeldung.
    "nick(), nicht string" ist ne Zumutung. Also (wenn Du willst)am Anfang auf NULL testen und meckern "Nickname ist NULL" und wenn beim testen der einzelnen Elemente von String "Unerlaubtes Zeichen im Nickname".

    Und korrigiere endlich Deinen Kommentar von "Definition einer Variablen vom 'Typ..."in Definition einer Function vom Typ..."

    Außerdem willst Du in Deiner Variante die Exception werfen wenn kein leerer String eingegeben wird nick != "". Du sollst sie aber werfen, wenn ein leerer String übergeben wird, also bei nick == "".

    Also drei Baustellen:
    1. prüfen ob NULL
    2. prüfen ob leerer String dazu zähle ich auch einen der nur aus Leerzeichen besteht. Also entweder trimmen oder von vorne bis hinten durchgehen ob ein Nichtleerzeichen drin vorkommt.
    3. prüfen ob unerlaubtes Zeichen im Nickname
    2 und 3 lassen sich zuusammen ermitteln, in dem Du durch den String durchläufst und dabei nicht nur testest, ob ungültiges Zeichen sopndern auch ob gültiges Zeichen vorhanden ist. Daher merkvariable vorher auf null setzen und bei gültigem Zeichen auf 1. Danach wenn keine unerlaubten Zeichen da natürlich sofort exception werfen) dann wenn >Merkvariable immer noch null ist auch ne Exception werfen ("keine gültigen Zeichen in Nick".

    und 4. bring endlich Deinen verdammten Quelltext in ne anständige Form!!! 😡

    Gruß Mümmel



  • 2 und 3 lassen sich zuusammen ermitteln, in dem Du durch den String durchläufst und dabei nicht nur testest, ob ungültiges Zeichen sopndern auch ob gültiges Zeichen vorhanden ist. Daher merkvariable vorher auf null setzen und bei gültigem Zeichen auf 1

    .

    Funktioniert nicht.Wenn ich nickname auf null setze, bekomme ich einenen Fehler:

    error: declaration of 'std::string nickname' shadows a parameter



  • Hi Helenchen,

    helenchen schrieb:

    2 und 3 lassen sich zuusammen ermitteln, in dem Du durch den String durchläufst und dabei nicht nur testest, ob ungültiges Zeichen sopndern auch ob gültiges Zeichen vorhanden ist. Daher merkvariable vorher auf null setzen und bei gültigem Zeichen auf 1

    .

    Funktioniert nicht.Wenn ich nickname auf null setze, bekomme ich einenen Fehler:

    error: declaration of 'std::string nickname' shadows a parameter

    Das war leider ein Schreibfehler von mir, da muss es 0 heißen.
    Und Du sollst ja auch in der Funktion nick nicht den Nicknamen auf Null setzen, sondern nur die Merkvariable. Nenn sie einfach GueltigVorhanden.
    Die Variable setzt Du beim erstellen in der Nick-Funktion gleich auf 0 und wenn du beim Parsen von Nickname ein gültiges Zeichen findest setzt Du GueltigVorhnden auf 1.

    Aufrufen kannst Du nick aber aus meiner sicht in Main trotzdem mit NULL

    nick( NULL );
    

    müsste zulässig sein, eventuell nach string gecastet. Aber es müsste auch ohne Cast gehen, denn NULL ist eigentlich zu allem zuweisungscompatibel.

    PS: Wo bleibt ein richtig formatierter Quelltext?

    Gruß Mümmel



  • Wie parst man einen String ( habe alles ausgegoogelt nicht gescheites)

    ⚠ Leider sieht mein Code katastrophal aus 👎 :

    #include <iostream>
    #include<stdexcept>
    using namespace std;
    
    // Definition einer Funktion vom Typ std::string namens nick (nickname):
    string nick (string nickname, string GueltigVorhanden=0){
    
       if(( nickname != GueltigVorhanden) || (nickname == GueltigVorhanden))
           throw runtime_error{ "nick(), nicht string"};
    
       else
           throw runtime_error{" nick(), string"};
    
       return nickname;
       }
    
    int main() {
    
    try{
        nick(NULL);   
    
       return 0;
    
        }
    
    catch ( const runtime_error& re ) {
    
    cerr << "Caught: " << re.what( ) << endl;
    
    return -1;
    
      }
    
    }
    

    gibt es da nicht andere Möglichkeit es zu machen ?
    😞
    PS: Je mehr ich über Exceptions lese desto schlimmer wird es 😃



  • Hinweis am Rande: installer dir mal ReSharper für C++ (mit Studentenausweis gratis) und drück CTRL+E und dann F für "Format Code" und poste erst dann Code.

    MfG SideWinder



  • Hi Helenchen,

    Eigentlich wollte ich ja nicht mehr antworten, wenn Du wieder unformatierten Müll postest, aber noch kurz nen Hinweis.

    helenchen schrieb:

    Wie parst man einen Strin1g ( habe alles ausgegoogelt nicht gescheites)
    gibt es da nicht andere Möglichkeit es zu machen ?

    kommt auf den jeweiligen Zweck an. In dem Fall ist es leicht:

    function nick
      int GueltigVorhanden = 0;
      wenn nick == NULL runtime_error{ "Nullwert übergeben"};
      Vom ersten bis zum letzten Zeichen gehen und jedes Zeichen angucken.
        wenn >= 'a' und <= 'z' oder >= 'A' und <='Z' 
            oder gleich ä oder gleich ö oder gleich ü 
            oder gleich Ä oder gleich Ö oder gleich Ü oder gleich ß 
          GueltigVorhanden = 1
        sonst
          wenn Zeichen != ' '
            throw runtime_error{ "verbotenes Zeichen"};
      wenn GueltigVorhanden == 0
        runtime_error{ "Leere Zeichenkette übergeben"};
    

    Nun musst Du nur noch ordentlichen Quelltext draus machen. Tipp von mir:ausgiebig klammern.

    PS: Je mehr ich über Exceptions lese desto schlimmer wird es 😃

    Nicht die Exceptions sind Dein Problem, sondern die Auswertung ob der String gültig ist.

    Ob er String in c++ von 1 bis n geht oder von 0 bis n-1 weiß ich nicht mehr. Der darunter liegende c_String geht auf jeden fall von 0 bis n-1 und an n liegt die /0 als Endekennzeichen. Im Notfall hätte ich den gezogen und ausgewertet. Auf dem Tablet kann ich aber auch nicht mehr als auf meinen Kopf zurückgreifen.
    Ich glaube mich aber zu erinnern, dass Du Anfang und Ende wie bei einem Vektor ermitteln konntest.
    Auch wenn Du wie SideWinder sagt ReSharper installierst solltest Du doch auch das Formatieren von Hand perfekt beherrschen. Es ist nur eine kleine Mühe und hilft beim Verstehen des Codes.

    Gruß Mümmel



  • Frage zum ReSharper , so wie ich gesehen habe gibt es dem nur für Visual Studio ich programmiere aber mit NetBeans. Klappt das nicht mit normalen Code Editor ( ich meine der das Code lesen kann wo es immer auch alles schön Aussieht 😃 )?



  • Hi Helenchen,

    einen Online-Formatierer für einen ersten Überblick findest Du hier.
    http://format.krzaq.cc/
    Du musst das Ergebnis aber noch ein wenig nacharbeiten.
    Ganz unten hast Du die Auswahl des Styles (nimm file) und den Button zum Starten.

    Gruß Mümmel



  • Hi Helenchen,

    mit dem Online-Formatierer überarbeitet sähe Dein Quelltext so aus:

    #include <iostream>
    #include <stdexcept>
    using namespace std;
    
    // Definition einer Funktion vom Typ std::string namens nick (nickname):
    string nick(string nickname, string GueltigVorhanden = 0)
    {
    
        if ((nickname != GueltigVorhanden) || (nickname == GueltigVorhanden))
            throw runtime_error{ "nick(), nicht string" };
    
        else
            throw runtime_error{ " nick(), string" };
    
        return nickname;
    }
    
    int main()
    {
    
        try
        {
            nick("capitalQ");
    
            return 0;
        }
    
        catch (const runtime_error& re)
        {
    
            cerr << "Caught: " << re.what() << endl;
    
            return -1;
        }
    }
    

    Ist schon mal nicht das verkehrteste, sauberer Allman-Stil, so wie ich ihn Dir ganz fest ans Herz legen würde.

    Und so würde ich es machen: (den Test auf NULL habe ich übrigens bei meinem Compiler nicht hinbekommen.)

    #include <iostream>
    #include <string>
    #include <stdexcept>
    
    using namespace std;
    
    // Definition einer Funktion vom Typ std::string namens nick (nickname):
    string nick(string nickname )
    {
      if ( nickname.empty() )                      // wenn leere Zeichenkette
        throw runtime_error( "NickName ist leer" );
    
      int GueltigVorhanden = 0;                    // Vorbelegen auf Falsch
      for ( std::string::iterator it=nickname.begin(); it!=nickname.end(); ++it)   // durch alle Zeichen gehen
      {
        if ( ( *it >= 33 ) && ( *it <= 126 ) )     // wenn erlaubtes ASCII-Zeichen ich hab hier mal
                                                   // auf alle druckbaren Zeichen erweitert (Test einfacher)
        {
          GueltigVorhanden = 1;                    // nicht nur Leerzeichen
        }
        else                                       // sonst wenn kein erlaubtes
        {
          if ( *it != ' ' )                        // und wenn es kein Leerzeichen ist
          {
            throw runtime_error( "Unzulässiges Zeichen" );  // muss es ein falsches sein, also Exception werfen
          }
        }
      }
      if ( GueltigVorhanden == 0 )
        throw runtime_error( "NickName enthält nur Leerzeichenn" );
      return nickname;
    }
    
    int main(int argc, _TCHAR* argv[])
    {
        string x;
        string Nick_Name;
      try
      {
        Nick_Name = nick( "\ncapitalQ" );
        cout << "Gültiger NickName eingegeben" << endl;
                                     // Eingabe damit Ergebnis sthen bleibt
        cout << "Eingabe für weiter" << endl;
        cin >> x;
    
        return 0;
      }
      catch (const runtime_error& re)
      {
        cerr << "Error: " << re.what() << endl;
        cout << "Eingabe für weiter" << endl;
        cin >> x;
        return -1;
      }
    }
    

    Gruß Mümmel



  • hier ist mein Code leider immer noch fehlerhaft

    #include <iostream>
    #include <stdexcept>
    #include <string>
    using namespace std;
    
    // Definition einer Funktion vom Typ std::string namens nick (nickname):
    string nick(string nickname)
    {
    
        int GueltigVorhanden = 0;
    
        if (nick == NULL)
            throw runtime_error{ " nick(), Nullwert übergeben " };
    
        for (size_t i = 0; i < nickname.size(); ++i)
            ;
        if (((nickname >= 'a' && nickname <= 'z' || nickname >= 'A' && nickname <= 'Z')
                || (nickname == 'ae' || nickname == 'oe' || nickname == 'ue'))
            || (nickname == 'AE' || nickname == 'OE' || nickname == 'UE' || nickname == 'SS'))
    
            GueltigVorhanden = 1;
    
        else if (nick != '')
            throw runtime_error{ " nick(), verbotenes Zeichen" };
        if (GueltigVorhanden == 0)
            throw runtime_error{ " nick(), Leere Zeichenkette übergeben" };
    }
    
    int main()
    {
    
        try {
    
            nick(NULL);
    
            return 0;
        }
    
        catch (const runtime_error& re) {
    
            cerr << "Caught: " << re.what() << endl;
    
            return -1;
        }
    }
    

    was meintest du hier Mümmelchen?

    wenn >= 'a' und <= 'z' oder >= 'A' und <='Z'
    oder gleich ä oder gleich ö oder gleich ü
    oder gleich Ä oder gleich Ö oder gleich Ü oder gleich ß

    und

    wenn Zeichen != ' '

    das sind die meist Fehlerhaften Zeilen bei mir . Habe ich da mal wieder was falsch verstanden? 🙄



  • Hi Helenchen,

    Zeichen != '' geht nicht, da muss zumindest ein Leerzeichen rein.
    Und den Rest solltest Du vernünftig ergänzen. Ich hab Dir nur hingeschrieben, was Du für Tests machen sollst.
    Ich hab Deine Fehler mal auskommentiert und etwas kommentiert. Bitte alles lesen.

    string nick(string nickname)
    {
    
        int GueltigVorhanden = 0;                         // soweit OK
    
    //    if (nick == NULL)                                          // hab ich nicht zum laufen bekommen
    //        throw runtime_error{ " nick(), Nullwert übergeben " }; // mein Compiler weigerte sich, mit NULL zu vergleichen
    
    //    for (size_t i = 0; i < nickname.size(); ++i) // nimm für Strings besser die Variante, die ich aufgeschrieben habe, 
                                                       // müsste aber auch so gehen.
    
            ;                                          // mit dem Semikolon als Schleifenkörper beendest Du die Schleife 
                                                       // ohne was zu tun.
    
    // Du vergleichst hier wirklich nen String mit nem einzelnen Zeichen???
    
    //    if (((nickname >= 'a' && nickname <= 'z' || nickname >= 'A' && nickname <= 'Z')
    //            || (nickname == 'ae' || nickname == 'oe' || nickname == 'ue'))             
    //        || (nickname == 'AE' || nickname == 'OE' || nickname == 'UE' || nickname == 'SS'))
    
    // ich hatte nicht umsonst geschrieben "Tip von mir: ausgiebig klammern"
    
    // ich würde mich nicht darauf verlassen, dass der Compiler 'ae' als 'ä' interpretiert
    
    // mache es besser so
        for (size_t i = 0; i < nickname.size(); ++i)
        {
            if (
                 ( ( nickname[ i ] >= 'a' ) && ( nickname[ i ] <= 'z' ) ) ||
                 ( ( nickname[ i ] >= 'A' ) && ( nickname[ i ] <= 'Z' ) ) ||
                 ( nickname[ i ] == 'ä' ) ||
                 ( nickname[ i ] == 'ö' ) ||
                 ( nickname[ i ] == 'ü' ) ||
                 ( nickname[ i ] == 'Ä' ) ||
                 ( nickname[ i ] == 'Ö' ) ||
                 ( nickname[ i ] == 'Ü' ) ||
                 ( nickname[ i ] == 'ß')
               )                               // mit Zeiger statt Indexzugriff wäre es performanter
                                               // geht aber auch so
            {
                GueltigVorhanden = 1;
            }
            else
            {
              if ( nickname[ i ] != ' ' )
              {
                throw runtime_error( " nick(), verbotenes Zeichen" );
              }
            }
        }
        if (GueltigVorhanden == 0)
        {
            throw runtime_error( " nick(), Leere Zeichenkette übergeben" );
        }
    }
    
    int main(int argc, _TCHAR* argv[])
    {
        string x;
    
        try {
    
            nick("/nOma");
    
            return 0;
        }
    
        catch (const runtime_error& re) {
    
            cerr << "Caught: " << re.what() << endl;
    
        cout << "Eingabe für weiter" << endl;
        cin >> x;
            return -1;
        }
        cout << "Eingabe für weiter" << endl;
        cin >> x;
    }
    

    Gruß Mümmel



  • leider meckert compiler auf die umlaute => multi - character char:

    #include <iostream>
    #include <stdexcept>
    #include <string>
    
    using namespace std;
    
    // Definition einer Funktion vom Typ std::string namens nick (nickname):
    string nick(string nickname)
    {
        if (nickname.empty()) // wenn leere Zeichenkette
            throw runtime_error("NickName ist leer");
    
        int GueltigVorhanden = 0; // Vorbelegen auf Falsch
        for (size_t i = 0; i < nickname.size(); ++i) // durch alle Zeichen gehen
        {
            if (
                   ((nickname[i] >= 'a') && (nickname[i] <= 'z'))
                || ((nickname[i] >= 'A') && (nickname[i] <= 'Z'))
                || (nickname[i] == 'ä')
                || (nickname[i] == 'ö')
                || (nickname[i] == 'ü')
                || (nickname[i] == 'Ä')
                || (nickname[i] == 'Ö')
                || (nickname[i] == 'Ü')
                || (nickname[i] == 'ß')
               )
            {
                GueltigVorhanden = 1; // nicht nur Leerzeichen
            }
            else // sonst wenn kein erlaubtes
            {
                if (nickname[i] != ' ') // und wenn es kein Leerzeichen ist
                {
                    throw runtime_error(
                        " nick(), verbotenes Zeichen "); // muss es ein falsches sein,
                    // also Exception werfen
                }
            }
        }
    
        if (GueltigVorhanden == 0) {
            throw runtime_error{ " nick(), Leere Zeichenkette übergeben" };
        }
    }
    
    int main()
    {
        string x;
    
        try {
            nick(" /ncapitalQ ");
    
            return 0;
        }
    
        catch (const runtime_error& re) {
            cerr << " Caught: " << re.what() << endl;
    
            cout << " Eingabe für weiter " << endl;
            cin >> x;
    
            return -1;
        }
        cout << " Eingabe für weiter " << endl;
        cin >> x;
    }
    

    habe versucht es durch setlocal zu beheben keine Chance 👎



  • Hi Helenchen,

    lass entweder die Umlaute weg, dann können im Nickname eben keine Umlaute verwendet werden, oder verwende den Numerischen Wert der Umlaute.
    Dabei musst Du dann aber ein wenig casten für den Vergleich.
    Entweder
    ( (int) nickname[i] == 196 ) // 196 = Ä, zumindest in Codeseite (Win-1252)
    oder
    ( nickname[i] == (char) 196 )
    Ich würde die zweite Form schöner finden, weil es ja auf einen char-Vergleich ankommt.
    Probiere notfalls aus, was die Umlaute bei Dir für einen Wert haben.
    Lies dazu ÄÖÜäöüß von der Konsoleneingabe (cin) ein und gib die einzelnen Zahlenwerte von den 7 Zeichen nach cout aus.
    etwa so

    string x;
    cout << "Gib die Umlautreihe ein" << endl;
    cin >> x;
    cout << (int) x[0] << '|' <<(int) x[1] << '|' << (int) x[2[e]cap[/e]] 
    << '|' << (int) x[3] << '|' << (int) x[4] << '|' << (int) x[5] << '|' << (int) x[6] << '|' <<  endl;
    

    Viel Erfolg, viel Spaß und eine gute Nacht wünscht Mümmel.

    PS: Gefährliche Falle, habs eben noch schnell korrigiert. Sieben Zeichen gehen ja von 0 nur bis 6 und nicht bis 7.

    Gruß Mümmel



  • muemmel schrieb:

    den Test auf NULL

    Wenn dann würde ich eh auf nullptr testen. Und verwirr bitte die Anfänger nicht mit _TCHAR und ähnlichem.



  • Hi Tyrdal,

    Tyrdal schrieb:

    muemmel schrieb:

    den Test auf NULL

    Wenn dann würde ich eh auf nullptr testen.

    Muss ich mal, wenn ein bisschen Zeit ist probieren.

    Und verwirr bitte die Anfänger nicht mit _TCHAR und ähnlichem.

    Das baut meine Entwicklungs-Umgebung so als Vorgabe zusammen. (c++Builder xe2)

    Gruß Mümmel



  • nullptr ist der aktuelle Standard und _TCHAR nicht, sondern Windows-spezifisch.


Anmelden zum Antworten