Suche vorschäge für Projekte



  • Hier mall ein Codeschnippsel:

    void codiren(string s_clear,string s_pass){
        s_pass=Pass(s_pass,s_clear.length());
        string codirt="codirt:";
        for(int i=0;i<(int)s_clear.length();i++){
            int i_clear;
            try{
                i_clear=getATOZtoNumer(s_clear[i]);
            }
            catch(fail_data_error error){
                std::cout<<std::endl<<"Error: char'"<<error.c_error<<"'not
    acapt. "<<std::endl;
                codirt+="...";
                break;
            }
            int i_pass;
            try{
                i_pass=getATOZtoNumer(s_pass[i]);
            }
            catch(fail_data_error error){
                std::cout<<std::endl<<"Error: char'"<<error.c_error<<"'not
    acapt. "<<std::endl;
                codirt+="...";
                break;
            }
            if(i_clear+i_pass-25>0)
                codirt+=getNumbertoAtoZ(i_clear+i_pass-26);
            else
                codirt+=getNumbertoAtoZ(i_clear+i_pass);
        }
    std::cout<<codirt<<std::endl;
    }
    


  • Dinge, die direkt auffallen:

    • Überall Pass-by-Value (auch Exceptions)
    • C-Casts
    • Falsche Typen ( int statt std::size_t ) und dadurch unnötige Casts
    • Überall mit Whitespaces gespart, dadurch nicht sehr leserlich (für mich zumindest)
    • Schlechte Einrückung ( try-catch )
    • i++ statt ++i, spielt später eine Rolle
    • Iteration mit Indizes statt Iteratoren, schränkt Code unnötig ein und ist je nach Datenstruktur langsamer
    • Etwas viel lokale Fehlerbehandlung mit Exceptions, sieht fast aus wie Java. Eventuell könnte man sich lokal Error-Codes überlegen oder die Exception propagieren...
    • Mix zwischen englischen und deutschen Bezeichnern
    • Inkonsistente Namenskonvention (Gross-/Kleinschreibung innerhalb Funktionsnamen)

    Siehe auch meinen letzten Post.


  • Mod

    codieren!
    http://www.duden.de/rechtschreibung/_ieren

    Bin ja eigentlich gegen Rechtschreibflames, aber wenn es jemand so oft falsch macht, dann tut's nach einer Weile einfach nur vom Zugucken weh.

    P.S.: Was Nexus zu dem Code sagt stimmt zwar, aber nach der Beschreibung deines Lernprozesses hat hier wohl jeder weitaus schlimmeres erwartet (die meisten Leute überschätzen sich nach C++-Kursen, da sie keine guten Vergleichsmaßstäbe haben). Das sind größtenteils nur kleinere Stilfragen, die man sich schnell angewöhnen kann.



  • @Nexus
    Habe da ein part fragen.
    Wo ist der unterschied zwischen i++ ++i?
    Was meinst du das mit den unnötige casts?
    Und könntest du mir ermorden wie du das mit den Fehlerbeheben meinst?

    Sorry muss noch viel lernen 😃



  • MaCo schrieb:

    Wo ist der unterschied zwischen i++ ++i?

    ++i: präfix increment = inkrementieren bevor der Ausdruck ausgewertet wird
    i++: postfix increment = inkrementieren nachdem der Ausdruck ausgewertet wurde

    i = 2;
    ++i*2; -> 6

    i = 2;
    2*i++; -> 4

    MaCo schrieb:

    Was meinst du das mit den unnötige casts?

    for(std::string::size_type i = 0;i < s_clear.length();i++);
    // beziehungsweise:
    for(std::size_t i = 0;i < s_clear.length();i++);
    

    Aber: Hier verweise ich nochmal darauf, wie er sagte, dass iteratoren besser sind.

    for (auto const& i : s_clear /* name: meh */) {
        // i ist vom typ "const char&"
    }
    // oder:
    for (auto i = std::begin(s_clear); i != std::end(s_clear); ++i) {
        // i ist vom type std::string::iterator
    }
    

    Etwas viel lokale Fehlerbehandlung mit Exceptions, sieht fast aus wie Java. Eventuell könnte man sich lokal Error-Codes überlegen oder die Exception propagieren...

    Er meint, dass so viel exception handling hier absoluter overkill ist und nicht der geschwindigkeit oder leslichkeit des codes zuträglich ist. Alternative Ansätze sind hier vorzuziehen (wie er sagte: fehlercodes zB)


  • Mod

    MaCo schrieb:

    Wo ist der unterschied zwischen i++ ++i?

    Die beiden Ausdrücke haben einen Rückgabewert. i++ gibt den ursprünglichen Wert von i wieder und ++i gibt den bereits erhöhten Wert von i wieder. Wenn du dir mal überlegst, wie das wohl umgesetzt wird, dann kommst du zu dem Schluss, dass dahinter wohl etwas in folgender Art stecken muss:

    int praefix_plusplus(int &i)
    {
      i += 1;
      return i;
    }
    
    int suffix_plusplus(int &i)
    {
      int old_value = i;
      i += 1;
      return old_value;
    }
    

    Wie man sieht, ist der zweite Code aufwändiger, da er eine Kopie erzeugt. Für einfache Datentypen ist der Unterschied in der Regel unerheblich, da das ganz leicht wegoptimiert werden kann, wenn der Rückgabetyp nicht benötigt wird (und selbst wenn er benötigt wird, kennt der Compiler vielleicht noch ein paar Tricks, um das zu optimieren). Aber wenn i kein int mehr ist, sondern irgendein kompliziertes Objekt (Beispiel: Checked Iterator in einer Baumstruktur), dann ist möglicherweise das Kopieren nicht ganz so einfach und der Compiler kann auch nicht wirklich tricksen, da er nicht mehr vorhersehen kann, wie sich i und i + 1 zueinander verhalten. Das macht Optimierung schwierig bis unmöglich. Wenn man dann i++ schreibt, obwohl man bloß ++i braucht, hat man unnötig das Programm langsamer gemacht.

    Was meinst du das mit den unnötige casts?

    Die Casts wie

    for(int i=0;i<(int)s_clear.length();i++){
    

    hast du doch nur gemacht, weil der Compiler sich darüber beschwert hat, dass du signed und unsigned Typen vergleichst, oder? Aber:
    1. Der Cast behebt das Problem gar nicht. Wenn du vor dem Vergleich einen unsigned Typen außerhalb des Wertebereichs des signed Typen in den signed Typen castest, dann passiert genau der gleiche Müll, als wenn du sie direkt verglichen hättest, ohne den Cast. Der Cast hat bloß den Compiler dazu gebracht, das Maul zu halten, weil du ihm gesagt hast, dass du weißt, was du an der Stelle tust. Tust du in Wirklichkeit aber gar nicht.
    2. Die eigentliche Ursache ist doch, dass i ein int ist, length() aber ein unsigned Typ (genauer: ein size_t). Mach doch i auch zu einem size_t!

    Und könntest du mir ermorden wie du das mit den Fehlerbeheben meinst?

    Das ist mir zu gewalttätig.



  • SeppJ schrieb:

    Wenn du vor dem Vergleich einen unsigned Typen außerhalb des Wertebereichs des signed Typen in den signed Typen castest, dann passiert genau der gleiche Müll, als wenn du sie direkt verglichen hättest, ohne den Cast. Der Cast hat bloß den Compiler dazu gebracht, das Maul zu halten, weil du ihm gesagt hast, dass du weißt, was du an der Stelle tust. Tust du in Wirklichkeit aber gar nicht.

    Nein. -1 < 2u ist false , weil -1 in einen unsigned gecastet wird und dann (im 2er-Komplement) den grösste Wert annimmt, den unsigned hat. Wenn man hingegen die rechte Seite in einen signed int castet, hat man das Problem nicht. Das einzige Problem, das man dann hat ist, wenn length()>MAX_INT. Und damit würde ich eher nicht rechnen. Deshalb ist der Cast nach int eine in der Praxis einwandfreie Lösung. size_t zu verwenden ist fehleranfällig (underflow ist mir schon öfters passiert) und die Probleme sind rein akademischer Natur.


  • Mod

    signature schrieb:

    SeppJ schrieb:

    Wenn du vor dem Vergleich einen unsigned Typen außerhalb des Wertebereichs des signed Typen in den signed Typen castest, dann passiert genau der gleiche Müll, als wenn du sie direkt verglichen hättest, ohne den Cast. Der Cast hat bloß den Compiler dazu gebracht, das Maul zu halten, weil du ihm gesagt hast, dass du weißt, was du an der Stelle tust. Tust du in Wirklichkeit aber gar nicht.

    Nein. -1 < 2u ist false , weil -1 in einen unsigned gecastet wird und dann (im 2er-Komplement) den grösste Wert annimmt, den unsigned hat. Wenn man hingegen die rechte Seite in einen signed int castet, hat man das Problem nicht. Das einzige Problem, das man dann hat ist, wenn length()>MAX_INT. Und damit würde ich eher nicht rechnen. Deshalb ist der Cast nach int eine in der Praxis einwandfreie Lösung. size_t zu verwenden ist fehleranfällig (underflow ist mir schon öfters passiert) und die Probleme sind rein akademischer Natur.

    😕 Das hab ich doch gesagt.

    P.S.: 💡 Oh, ich hab's. Ich hab "genau" geschrieben, obwohl es doch noch einen nicht erwähnten Unterschied gab. Schande über mich, dass ich wieder nicht gemerkt habe, dass ich hier doch in der Matheklausur bin und nicht in einem Forum in dem man mit normalen Menschen mit Umgangssprache kommuniziert.



  • Trotzdem: casts sind nicht (immer) kostenlos.



  • Tim06TR schrieb:

    Trotzdem: casts sind nicht (immer) kostenlos.

    unsigned int -> int aber schon.



  • Ich habe mal versucht so viele Anregungen die verstanden haben um zu setzten. Ist das so besser?

    void codiren(string s_clear,string s_pass){
    	s_pass=Pass(s_pass,s_clear.length());
    	string codirt="codirt:";
    	for(size_t i=0;i<s_clear.length();++i){
    		int i_clear,i_pass;
    		try{
    			i_clear=getatoztonumer(s_clear[i]);
    			i_pass=getatoztonumer(s_pass[i]);
    		}
    		catch(fail_data_error error){
    			std::cout<<std::endl<<"Error: char'"<<error.c_error<<"'not acapt. "<<std::endl;
    			codirt+="...";
    			break;
    		}
    		if(i_clear+i_pass-25>0)
    			codirt+=getnumbertoatoz(i_clear+i_pass-26);
    		else
    			codirt+=getnumbertoatoz(i_clear+i_pass);
    	}
    	std::cout<<codirt<<std::endl;
    }
    

    Was würdet ihr mir vorschlagen um mir gute Grundlagen zu lernen? Bis her habe ich immer nur versucht das meine Programme irgendwie lauft, ich würde aber gerne mehr verstehen und effizienter Code schreiben. Was für Literatur würdet ihr mir empfehlen?



  • Hier findest du eine gute Liste von Büchern, die auch ständig aktuell gehalten wird.



  • gibt es auch gute Bücher in deutsch? Ich weise zwar das ich später um englisch nicht vorbeikomme, würde aber anzufangen aus Verständnis Schwierigkeiten lieber mit deutscher Lektüre anfangen.



  • MaCo schrieb:

    Ist das so besser?

    Den zuerst genannten (pass by value) und aus meiner Sicht wichtigsten Punkt hast du noch nicht beachtet.
    Und nochmal: dieses 'codirt' versteht man nicht, da man (oder zumindest ich) da was englisches rein interpretiere (co-dirt, 'gemeinsamer Dreck'?).



  • Okey das mit den Namen muss ich verandern.
    Ich versteh nur leider nicht was ihr mir (pass by value) meint; Was muss wann anders/warum?



  • Übergib Objekte als Wert (by Value), wenn du eine Kopie oder ein Move (Besitz-Transfer) möchtest. Oder falls es sich um einfache Typen handelt.

    Ansonsten, übergib Objekte als Referenzen (oder Zeiger).



  • Ist das so richtig angewandt?

    i_clear=getatoztonumer(&s_clear[i]);
    
    int getatoztonumer (char* c_char){
    	//a[97]-z[122]|A[65]-Z[90]
    	if((*c_char>=97&&*c_char<=122)||(*c_char>=65&&*c_char<=90)){
    		if(*c_char>=97&&*c_char<=122){
    			return *c_char-97;
    		}else{
    			return *c_char-65;
    		}
    	}else{
    		throw fail_data_error(*c_char);
    		return 0;
    	}
    }
    


  • Nö, gefällt mir überhaupt nicht.

    - 100% Prozent deine Funktionen enthalten Rechtschreibfehler. Codiren soll vermutlich Codieren heissen und getatoztonumer getatoztonummer . Oder getatoztonumber . Nachdem du das korrigiert hast solltest du dir Gedanken über sinnvolle Bezeichnungen machen. Codieren . Gut. In welches Format? Und was genau macht die Funktion? Trenne nach Aufgabenbereich. Codieren nimmt zwei strings entgegen und gibt irgendwas aus. Das solltest du in zwei Schritte aufteilen: 1. Codieren und 2. Ausgabe. Und dass du call-by-reference statt call-by-value benutzten sollst hat man dir ja auch schon gesagt.
    Ähnliches gilt für getatoztonumer . Was soll get a to z to number ausdrücken? encode_letter fände ich da wesentlich aussagekräftiger.

    Zum letzten Schnipsel:

    - deine Funktion gibt eine positive Ganzzahl zurück. Warum also int und nicht unsigned int (oder unsigned char )?

    - du übergibst einen Zeiger auf einen char . Warum? Warum nicht direkt den char übergeben? Und falls es unbedingt ein Zeiger sein muss solltest du auch prüfen, ob er auf irgendwas zeigt.

    - Doppelte Vergleiche: Du führst die Vergleiche doppelt durch: Einmal, um zu gucken, ob der Wertebereich generell eingehalten wird und ein zweites Mal, um zwischen Klein- und Großschrift zu unterscheiden.

    - In diesem Fall finde ich das Rechnen mit Buchstaben besser als mit ASCII Werten. if( c >= 'a' ) ist wesentlich besser zu verstehen als if( c >= 97 ) .

    Meine bescheidene Meinung.


Anmelden zum Antworten