neuer Lehrer, neues Schuljahr, neues "C++"



  • Hallo Leute,

    ich brauche mal einen Tipp von euch 🕶
    habe jetzt das dritte Jahr programmieren in der Schule und so wie es das Schicksal will, dieses Jahr einen neuen Prof..
    Was ich mit gutem Gewissen über meine Programmierkünste sagen kann ist, dass mein Programmierstil ein Mix zwischen C, C++ und den guten Headerdateien von Borland geworden ist.
    Nur gut das wir jetzt in Linux c++ programmieren und ich wieder von vorne anfangen kann.. 😕
    Deswegen hab ich mir vorgenommen, dass ich das jetzt richtig anpacken muss und dank Axelh1992 wurde mir das noch deutlicher vor Augen geführt.

    Also nun zu meiner Frage:

    #include <iostream>  //std::cin / std::cout / std::endl 
    #include <iterator>  //std::istream_iterator 
    #include <numeric>   //std::accumulate 
    
    int main() 
    { 
        std::cout << std::accumulate(std::istream_iterator<int> (std::cin), std::istream_iterator<int>(), 0) << std::endl; 
    }
    

    In keinem meiner Bücher kommt dieser Art der Programmierung vor...
    Hab das jedoch schon mal bei einem Freund gesehen, der Inf. studiert, also kann das nicht so schlecht sein.

    Das diese Zeilen Zahlen zusammenzählen können, kann ich einfach nicht erkennen.
    Wie soll man den nun programmieren, um darauf aufbauen zu können? Und wie wird eigentlich "richtig", also im Programmierer-Alltag gearbeitet?

    Grüße



  • Aho schrieb:

    Nur gut das wir jetzt in Linux c++ programmieren und ich wieder von vorne anfangen kann.. 😕

    Das ist tatsächlich gut - dadurch lernst du nämlich endlich mal ein portables Standard-C++ und nicht einen Mischmasch den du nur auf Windowssystemen mit Borland-Compiler benutzen kannst. Das Schlimme ist also nicht, dass der neue Lehrer euch was anderes beibringt, sondern dass der alte Lehrer euch so einen Mist beigebracht hat. Bibliotheken - auch die von Borland - müssen nicht unbedingt schlecht sein. Schlecht ist nur wenn man nicht weiß wo der Sprachstandard aufhört und die Bibliothek anfängt.

    Aho schrieb:

    Also nun zu meiner Frage:

    #include <iostream>  //std::cin / std::cout / std::endl 
    #include <iterator>  //std::istream_iterator 
    #include <numeric>   //std::accumulate 
    
    int main() 
    { 
        std::cout << std::accumulate(std::istream_iterator<int> (std::cin), std::istream_iterator<int>(), 0) << std::endl; 
    }
    

    In keinem meiner Bücher kommt dieser Art der Programmierung vor...
    Hab das jedoch schon mal bei einem Freund gesehen, der Inf. studiert, also kann das nicht so schlecht sein.

    Das diese Zeilen Zahlen zusammenzählen können, kann ich einfach nicht erkennen.
    Wie soll man den nun programmieren, um darauf aufbauen zu können? Und wie wird eigentlich "richtig", also im Programmierer-Alltag gearbeitet?

    Was ist jetzt die Frage? Womit hast du Probleme? Wenn Teile aus der Standardbibliothek verwendet werden, die du noch nicht kennst, solltest du einen Blick in die Referenz deiner Wahl werfen. z.B. www.cplusplus.com/reference



  • Das klingt jetzt vieleicht etwas komisch...
    habe bis jetzt immer cin, cout, printf ... verwendet.
    Die ganzen "::" verwirren mich total, hab die noch nie verwendet.
    genauso geht es mir mit den seltsamen befehlen wie "accumulate", ist das die standard-sprache?

    ich hätte ja so ein Programm, das Zahlen miteinander addiert einfach mit einer while-Schleife gemacht, die bei x abbricht.
    Aber so wie das geschrieben ist, kann ich mir überhaupt nichts darunter vorstellen.

    Diese <> kenne ich nur von größer, kleiner
    std kenne ich nur von using namespace.std
    und <iterator> ?? was kann diese headerdatei



  • Aho schrieb:

    Das klingt jetzt vieleicht etwas komisch...
    habe bis jetzt immer cin, cout, printf ... verwendet.
    Die ganzen "::" verwirren mich total, hab die noch nie verwendet.
    genauso geht es mir mit den seltsamen befehlen wie "accumulate", ist das die standard-sprache?

    :: ist der Scope-Operator, er gibt hier den Namensraum std an. Stattdessen habt ihr wahrscheinlich using namespace std; geschrieben. std::accumulate() ist eine Funktion der Standardbibliothek (genauer ein Funktionstemplate), das Werte "akkumulieren" kann, standardmässig also einfach addiert. Mehr dazu steht auf der von pumuckl verlinkten Seite.

    Aho schrieb:

    ich hätte ja so ein Programm, das Zahlen miteinander addiert einfach mit einer while-Schleife gemacht, die bei x abbricht.
    Aber so wie das geschrieben ist, kann ich mir überhaupt nichts darunter vorstellen

    Du kannst auch mit einer Schleife das gleiche bewirken. Was du hier siehst, ist massiver Einsatz der STL, einem Teil der C++-Standardbibliothek. Das ermöglicht teilweise sehr elegante und kurze Schreibweisen. Aber das ist schon relativ fortgeschrittenes Niveau; bevor man das anwendet, sollte man die anderen Grundlagen (prozedurale Programmierung, Funktionen, Klassen, Templates) verstanden haben.



  • Danke 🙂

    Container und Iteratoren
    dh: alles was die Laufzeitbibliothek zu bieten hat sollte man verwenden.
    sehe gerade, dass in meinem Buch C und C++ Laufzeitbibliotheken drin sind.
    Habs mir jetzt nicht genauer angeschaut aber wenn, dann sollte ich die beiden nicht kombinieren oder ist das nicht so fatal?



  • Aho schrieb:

    Also nun zu meiner Frage:

    #include <iostream>  //std::cin / std::cout / std::endl 
    #include <iterator>  //std::istream_iterator 
    #include <numeric>   //std::accumulate 
    
    int main() 
    { 
        std::cout << std::accumulate(std::istream_iterator<int> (std::cin), std::istream_iterator<int>(), 0) << std::endl; 
    }
    

    Und wie wird eigentlich "richtig", also im Programmierer-Alltag gearbeitet?

    So nicht. Keinem User kannst du ein Programm verkaufen, bei dem er die Eingabe mit Strg+Z beenden muss. Aber dass man namespaces wie std:: verwendet ist normal. Bei richtigen Programmen sollte man versuchen seinen Code möglichst klar und einfach zu formulieren und nicht so ein Poser C++ wie "std::accumulate(std::istream_iterator<int> (std::cin), std::istream_iterator<int>(), 0)" verwenden. Ansonsten http://www.c-plusplus.net/forum/viewtopic-var-t-is-245729-and-start-is-0-and-postdays-is-0-and-postorder-is-asc-and-highlight-is-.html


  • Mod

    C++Poser schrieb:

    So nicht. Keinem User kannst du ein Programm verkaufen, bei dem er die Eingabe mit Strg+Z beenden muss.

    Ähh, sämtliche Unix Kommandozeilentools?



  • SeppJ schrieb:

    Ähh, sämtliche Unix Kommandozeilentools?

    Abgesehen davon, dass in diesem Fall jede "Nicht-Int-Eingabe" auch zum Ende führt.



  • SeppJ schrieb:

    C++Poser schrieb:

    So nicht. Keinem User kannst du ein Programm verkaufen, bei dem er die Eingabe mit Strg+Z beenden muss.

    Ähh, sämtliche Unix Kommandozeilentools?

    Na, die paar Randgruppen User machen weniger als ein Prozent aus.



  • C++Poser schrieb:

    SeppJ schrieb:

    C++Poser schrieb:

    So nicht. Keinem User kannst du ein Programm verkaufen, bei dem er die Eingabe mit Strg+Z beenden muss.

    Ähh, sämtliche Unix Kommandozeilentools?

    Na, die paar Randgruppen User machen weniger als ein Prozent aus.

    Ignoranz ist schön und gut und kann einen vorwärts bringen, aber bitte nicht so übertrieben heraus posaunen.

    C++Poser schrieb:

    Bei richtigen Programmen sollte man versuchen seinen Code möglichst klar und einfach zu formulieren und nicht so ein Poser C++ wie "std::accumulate(std::istream_iterator<int> (std::cin), std::istream_iterator<int>(), 0)" verwenden.

    Ähm, ich finde gerade solche Einzeiler besonders schön! Auch wenn das mit dem istream_iterator sicherlich Geschmacksache ist. Dann lager ich die Eingabe der Daten in eine eigene Methode/Klasse aus, die dem User bessere Möglichkeiten zur Kontrolle/Übersicht an die Hand gibt, und speicher die Daten in einem vector. Diesen Vector kann ich dann wieder an accumulate übergeben und mit nur einer Zeile die Daten entsprechend dem übergebenen BinaryOperator verwurschteln.

    Ich bin echt erstaunt, wie manche Leute sich immer aufregen, dass C++ zu wenig Funktionen bietet und man immer auf externe Libs angewiesen ist, und dann trotzdem Leute kommen und genau diese schönen Möglichkeiten noch verteufeln. Geh und spiel Java...



  • Angry Larry schrieb:

    Ich bin echt erstaunt, wie manche Leute sich immer aufregen, dass C++ zu wenig Funktionen bietet und man immer auf externe Libs angewiesen ist, und dann trotzdem Leute kommen und genau diese schönen Möglichkeiten noch verteufeln. Geh und spiel Java...

    Davon, daß man in Template-Meta-Code Primzahlen berechnen kann, wird kein einziger Buchstabe auf dem Bildschirm rot. C++ hat keine threads, kein Netzwerk, keine Farben, ungefähr nichts. Und ich finde diese Einzeiler sind übertrieben und wirklich häßlich.



  • Aho schrieb:

    Das diese Zeilen Zahlen zusammenzählen können, kann ich einfach nicht erkennen.

    Och, daran gewöhnt man sich recht schnell.

    Wie soll man den nun programmieren, um darauf aufbauen zu können?

    So nicht.

    Und wie wird eigentlich "richtig", also im Programmierer-Alltag gearbeitet?

    Auch so. Keiner wird Dich zwingen, Poser-Code zu schreiben, aber lesen wirst Du ihn immer wieder. Und die Poser machen das nicht böswillig. Die glauben echt daran, daß das vernünftig sei. Und sie sagen, daß jeder, der anderere Meinung ist, das einfach nicht versteht und seine Meinung auf purer Unwissenheit begründet.
    Vor ein paar Jahren war's in der C-Gemeinde genauso, wer da nicht flüssig Sachen wie while(*dst++=*src++) geschrieben und gelesen hat, galt als doof. Es hat viele Jahre gebraucht, bis erste Zaghafte Versuche gemacht werden durften, bewußt lesbaren Code zu schreiben.



  • 123
    123
    a
    246

    Sonderlich elegant ist das für den User sicher nicht. Er weiß nicht, was das Programm macht und bricht nur zufällig mit einer Nichtzahl ab.

    Bei der Eingabe einer Float-Zahl wird es ganz düster:

    1.23
    1

    So liest sich das Programm zumindest kompakter:

    #include <iostream>  // cin, cout, endl
    #include <iterator>  // istream_iterator
    #include <numeric>   // accumulate
    
    using namespace std; // opens namespace standard (std)
    
    int main()
    {
        cout << accumulate(istream_iterator<int>(cin), istream_iterator<int>(), 0) << endl;
    }
    

    Es gibt drei Dinge, auf die ich zunächst achten würde:

    1. Usability: Das Programm ist für den User da. Der soll es intuitiv verstehen. Fehler und Zeitverluste sollen vermieden werden.

    2. Lesbarkeit des Programms: Es gibt immer einen Nachfolger/Kollegen, der daran weiter arbeiten soll.

    3. Grenzverletzungen abfangen:

    1000000000000000000
    0

    🙄

    ... und schon liegt der hübsche Käfer komplett auf dem Rücken. 😉



  • Erhard Henkes schrieb:

    Bei der Eingabe einer Float-Zahl wird es ganz düster:

    1.23
    1

    Das wird aber auch bei einer selber geschriebenen Methode zum Enlesen nicht besser, wenn Integer erwartet wird und deshalb auch cin.operator>> auf nen integer losgelassen wird.



  • Das wird aber auch bei einer selber geschriebenen Methode zum Enlesen nicht besser, wenn Integer erwartet wird und deshalb auch cin.operator>> auf nen integer losgelassen wird.

    Richtig. Daher muss das Programm diesbezüglich eben entsprechend prüfen / agieren.



  • Deshalb sollte man auch lieber immer char s einlesen. Man kann ihn dank stringstreams ja immernoch in Zahlen konvertieren.
    Ob's den Aufwand wert ist, weiß ich nicht.

    Poser-Code ist so eine Sache. Die Grenzen von Posercode sind ja nicht mal richtig definiert, ist also sowieso Geschmacksache. Aber wenn man schon Posercode wie das wunderbare STL-Stück da oben benutzt (was ich übrigens auch "bewundere" 🙂 ), dann sollte man zumindest kommentieren, was er macht, bzw. in eine Inline-Funktion stopfen und ihr einen treffenden Namen geben, z.B. add_userinput() oder was weiß ich. Damit würde ich klarkommen:

    // liest Zahlen ein, summiert sie und gibt sie aus
    cout << accumulate(istream_iterator<int>(cin), istream_iterator<int>(), 0) << endl;
    

    Aber in C++ sind ja so manche Sachen kryptisch...



  • @ad acta: accumulate ist doch deutlich genug!?
    ich glaube nicht, dass man solche zeilen noch extra kommentieren sollte...
    1 blick sagt da doch alles aus:
    accumulate -> addieren
    istream_iterator -> einlesen

    ich finde solchen code übrigens viel leserlicher als das ganze "per hand" zu machen...

    bb



  • Angry Larry schrieb:

    C++Poser schrieb:

    SeppJ schrieb:

    C++Poser schrieb:

    So nicht. Keinem User kannst du ein Programm verkaufen, bei dem er die Eingabe mit Strg+Z beenden muss.

    Ähh, sämtliche Unix Kommandozeilentools?

    Na, die paar Randgruppen User machen weniger als ein Prozent aus.

    Ignoranz ist schön und gut und kann einen vorwärts bringen, aber bitte nicht so übertrieben heraus posaunen.

    C++Poser schrieb:

    Bei richtigen Programmen sollte man versuchen seinen Code möglichst klar und einfach zu formulieren und nicht so ein Poser C++ wie "std::accumulate(std::istream_iterator<int> (std::cin), std::istream_iterator<int>(), 0)" verwenden.

    Ähm, ich finde gerade solche Einzeiler besonders schön! Auch wenn das mit dem istream_iterator sicherlich Geschmacksache ist. Dann lager ich die Eingabe der Daten in eine eigene Methode/Klasse aus, die dem User bessere Möglichkeiten zur Kontrolle/Übersicht an die Hand gibt, und speicher die Daten in einem vector. Diesen Vector kann ich dann wieder an accumulate übergeben und mit nur einer Zeile die Daten entsprechend dem übergebenen BinaryOperator verwurschteln.

    Ich bin echt erstaunt, wie manche Leute sich immer aufregen, dass C++ zu wenig Funktionen bietet und man immer auf externe Libs angewiesen ist, und dann trotzdem Leute kommen und genau diese schönen Möglichkeiten noch verteufeln. Geh und spiel Java...

    Tja, muss dich enttäuschen. Ich programmier beruflich C++ und dass was bei uns am meisten von der StdLib verwendet wird sind die container der Rest ist vernachlässigbar. Vielleicht noch for_each, aber da auch mehr die boost Variante bzw. zusammen mit boost bind. Den größten Teil machen 3rd Party Libs wie z.B. QT für GUI aus. Da gibts mit QString auch nen String mit dem man seine SW einfacher auf den asiatischen Markt bring, als mit std::string. Aber vielleicht verdienst du ja dein Geld mit Kommandozeilentools mit besonders schönen Einzeilern und BinaryOperator verwurschteln.


  • Administrator

    @Aho,
    Ich empfehle dir beiden Parteien zu folgen 🙂
    Dies heisst: Verwende beide Möglichkeiten, wo es jeweils Sinn macht. Man kann in beide Richtungen übertreiben, kompletter Verzicht auf die STL oder völlig krankhafter Einsatz der STL. Wann was Sinn macht, dass ist schwer zu definieren und meistens eine recht subjektive Angelegenheit.
    Die wichtigsten Punkte zu beachten sind:
    - Du musst es lesen und verstehen können.
    - Dein Nachfolger muss es lesen und verstehen können.

    Bei deinem gezeigten Beispiel sehe ich zwei Probleme:
    1. Wie Erhard Henkes es angesprochen hat, wird die Eingabe nicht sauber überprüft. In diesem Code eine gute Fehlerprüfung für die Eingabe einzubauen, dürfte eher schwer sein.
    2. Es ist viel zu kompakt und alles in einer Zeile. Wenn man es nur schon ein wenig auseinandernehmen würde, würde dies die Lesbarkeit deutlich erhöhen:

    #include <iostream>  // cin, cout, endl
    #include <iterator>  // istream_iterator
    #include <numeric>   // accumulate
    
    int main()
    {
        int const init = 0; // Fakultativ, aber vielleicht verständlicher, als eine einfache 0 als Argument.
                            // Man erkennt, wofür der Parameter verwendet wird.
        std::istream_iterator<int> inputIterEnd;
        std::istream_iterator<int> inputIterBegin(std::cin);
    
        int total = std::accumulate(inputIterBegin, inputIterEnd, init);
        std::cout << total << std::endl;
    
        return 0;
    }
    

    @C++Poser,
    Und weil eure Firma es so macht, muss es gleich für den ganzen Markt gelten, oder wie soll man dich verstehen? 🙂

    Grüssli



  • Wenn mir einer sowas abliefert,

    int summe=0;
    
    int zahl;
    while(cin>>zahl)
       summe+=zahl;
    
    cout<<summe;
    

    wäre ich nicht wirklich sauer.


Anmelden zum Antworten