Undefinierter Integer [gelöst]



  • @Unterfliege sagte in Undefinierter Integer:

    Wenn du lieber int benutzen willst und den negativen Bereich nicht brauchst oder, kannst du auch Werte <0 nehmen oder ansonsten auch dafür max().

    Bei int würde ich eher min() nehmen. Mit max() würdest du die Asymmetrie zwischen max. nutzbarem negativem Wert und max. nutzbarem positiven Wert nur noch grösser machen - mit min() dagegen würde man sie ausgleichen. Zugegeben, ist jetzt wohl meistens wörscht, aber finde ich konzeptionell irgendwie schöner.



  • Vielen Dank für eure ganzen Antworten! Der konkrete Anwendungsfall ist, dass ich vordefinierten Kategorien Werte zuweisen möchte. Diese sollen in einer .txt Datei gespeichert und bei Bedarf wieder ausgelesen werden. Zur Vereinfachung nur die Input Funktion:

    #include <iostream>
    #include <string>
    #include <fstream>
    
    int getValue (std::string concreteCategory, int inputValue = 0){
        std::cout << concreteCategory <<": ";
        std::cin >> inputValue;
        return inputValue;
    }
    
    int main () {
        std::string categories[4] ={"test", "test1", "test2", "test3"};
        int categoryValue[4];
        std::fstream test;
        for (int i = 0; i<4; i++){
            categoryValue[i] = getValue (categories[i]);
        }
        test.open("test.txt", std::ios::out | std::ios::app);
        for (int i = 0; i<4; i++){
            test << categories[i] << std::endl <<categoryValue[i] << std::endl;
        }
        test.close();
        return 0;
    }
    
    

    Im Anschluss soll mitcategoryValue [] und den konkreten Werten in Abhängigkeit zu den Kategorien gerechnet werden. Wenn ich also eine Kategorie + Wert aus der Rechnung ausschließen möchte, muss der Wert undefiniert bleiben. Negative Zahlen funktionieren deshalb als Ausschlusskriterium nicht. Aber wie vorgeschlagen, kann ich ja einfach einen Float statt eines Integers verwenden.



  • Ich habe deine Version mal modernisiert, damit du eine Orientierung hast, wie man das auch machen kann 😇
    Dein Quellcode ist schon gut, aber es gibt halt immer noch ein paar Dinge, die man besser machen kann, bei jedem Entwickler übrigens 😉 Und manches ist halt auch einfach Geschmackssache. 😁

    #include <iostream>
    #include <string>
    #include <fstream>
    #include <vector>
    
    
    void enterValueForCategory( std::pair<std::string, int> &mypair )
    {
        std::cout << mypair.first <<": ";
        std::cin >> mypair.second;
    }
    
    
    int main () {
        std::vector<std::pair<std::string, int>> CategoryValuePairs = { { "test", 0 }, { "test1", 0 }, { "test2", 0 }, { "test3", 0 } };
        // Values eingeben
        for ( auto &mypair : CategoryValuePairs )
            enterValueForCategory( mypair );
    
        std::ofstream fileOut( "test.txt", std::ios::app );
        if ( !fileOut.good() )
        {
            // Fehlerzustand
            return -1;
        }
    
        // Ausgabe in Datei
        for ( auto &mypair : CategoryValuePairs )
            fileOut << mypair.first << "\n" << mypair.second << "\n";
        return 0;
    }
    
    

    Stichworte:

    • sprechende Funktionsnamen
    • passende Strukturen auswählen ( in dem Fall bietet sich das std::pair regelrecht an )
    • Fehlerzustände prüfen ( z.B. von Dateien )


  • @It0101 Sehr nice, vielen Dank für deine Mühe! An deinen Vorschlägen habe ich erstmal ein bisschen zu knabbern 😃 Und ja.... sprechende Funktionsnamen habe ich immer noch nicht so raus. Die Hinweise auf std::pair und ios::good() sind auch top!



  • @Richard_Wunsch sagte in Undefinierter Integer [gelöst]:

    @It0101 Sehr nice, vielen Dank für deine Mühe! An deinen Vorschlägen habe ich erstmal ein bisschen zu knabbern 😃 Und ja.... sprechende Funktionsnamen habe ich immer noch nicht so raus. Die Hinweise auf std::pair und ios::good() sind auch top!

    ist alles kein MustHave, aber manches ist Nice2Know 😉 Wenn du Fragen hast, immer raus damit.



  • Besser wäre is_open() statt good().



  • @spiri sagte in Undefinierter Integer [gelöst]:

    Besser wäre is_open() statt good().

    Ich glaube bei taufrischen jungfräulichen Stream-Objekten ist das egal. Wenn das Objekt natürlich vorher schonmal benutzt wurde, kann eines der FailBits noch gesetzt sein und man bekommt bei good() false zurück obwohl die Datei offen ist.
    Da ich aber generell keine Stream-Objekte recycle, ist das für mich egal 😉



  • Hm...

    meine erste Intuition wäre hier eigentlich eher eine map von Schlüssel auf Wert gewesen. Wenn der Schlüssel nicht in der map vorkommt, ist der Wert nicht gesetzt. Der von @It0101 vorgeschlagene std::vector<std::pair<std::string, int>> hätte lediglich den Vorteil, dass die Reihenfolge der Werte gleich bleibt. Ansonten würde ich std::map<std::string, int> vorschlagen (oder auch unordered_map). So eine Map könnte man auch problemlos nach json/yaml oder was auch immer schreiben und von da auslesen (geht mit dem vector natürlich auch). Ich würde also eine fertige Bibliothek dafür nehmen.



  • @wob
    In dem geposteten Beispiel sucht er aber nicht gezielt nach Keys/Strings. Daher schien mir die unordered_map unpassend.
    Kann man aber genauso nehmen. In dem Beispiel machts aber funktional keinen Unterschied. Und die Performance vom vector dürfte bei nur 4 Einträgen besser sein, selbst wenn man nach Keys sucht 😉



  • @It0101 Nur noch eine kleine Anmerkung: wenn die Größe zur compile time feststeht und sich nicht ändern soll, würde ich eher std::array empfehlen. Ist dann auch das genaue Equivalent zu dem verwendeten C-Style Array.



  • @Unterfliege sagte in Undefinierter Integer [gelöst]:

    @It0101 Nur noch eine kleine Anmerkung: wenn die Größe zur compile time feststeht und sich nicht ändern soll, würde ich eher std::array empfehlen. Ist dann auch das genaue Equivalent zu dem verwendeten C-Style Array.

    Das sind Details. In der Praxis hab ich noch nie einen passenden Anwendungsfall für std::array gehabt, weil die meisten Sachen in der Serverentwicklung konfigurierbar sind. Daher ist es für Anfänger wesentlich wichtiger, std::vector zu beherrschen.



  • @It0101 sagte in Undefinierter Integer [gelöst]:

    In dem geposteten Beispiel sucht er aber nicht gezielt nach Keys/Strings. Daher schien mir die unordered_map unpassend.

    Naja, das hatte ich anders verstanden. Vordefinierten Kategorien sollen Werte zugewiesen werden - und diese Werte können fehlen.

    Das passt doch exakt zur map: ich muss nachgucken, ob es einen vordef. Wert gibt (map.find) und diesen, wenn vorhanden, dann zuweisen.

    Kann aber natürlich sein, dass das Problem anders gelagert ist. Die "was ist schneller"-Diskussion möchte ich nicht mitführen, weil man hier die für das Problem logisch richtige Datenstruktur wählen sollte.



  • Auf den ersten Blick, denke ich auch, dass std::map besser geeignet ist. Ich würde es gerne nach folgendem Muster benutzen.

    #include <map>
    #include <string>
    #include <iostream>
    
    int main()
    {
        int x;
        int y;
        std::map <std::string, std::map<int,int>> test= {"test",{1,x+y}};
        return 0;
    }
    

    Dabei ist der string der Name der Kategorie, der erste Integer der Wert und der zweite Integer die Formel, nach der gerechnet werden soll. Kann das so theoretisch überhaupt funktionieren und wie initalisiere ich diese Map richtig?



  • @Richard_Wunsch So wie du das jetzt hast, wird als Wert der inneren Map das Ergebnis von x + y gespeichert. Das ist in dem Fall aber sogar, da x und y nicht initialisiert sind, undefiniert.
    Um die Formel zu speichern, musst du eine Funktion in der Map speichern. Das machst du wahlweise über Funktionspointer bzw. std::function. Wahlweise könntest du das wohl auch über Funktoren hinbekommen.
    Verwenden denn alle Formeln nur x und y oder auch noch andere Parameter?

    Oder wiederum verstehe ich dich komplett falsch und die willst die Formel einfach als String speichern, um sie auszugeben?



  • @Unterfliege Ok, initalisieren habe ich gelöst. Waren ein paar Klammern zu wenig...

    #include <map>
    #include <string>
    #include <iostream>
    
    int foo (int x, int y){
        return (x+y);
    }
    
    int main(){
        std::map <std::string, std::map <int,int>> test = {{"test",{{1,foo(1,1)}}}};
    }
    

    Das eigentliche Ziel ist es, einen Werte (erster integer) einzulesen, einer vordefinierten Kategorie zuzuweisen (string) und dann in die Rechnung (zweiter integer) mit einzubinden. Also quasi so etwas: ["Kategorie"] = [x+y] - [eingelesener Wert]

    Edit: Wichtig dabei ist, dass wenn kein Wert eingelesen wird, die gesamte Kategorie undefiniert bleibt.



  • @Richard_Wunsch sagte in 3d map initialisieren:

    Das eigentliche Ziel ist es,

    Habe die Erklärung leider nicht verstanden.

    Jetzt hast du eine Datenstruktur, die so aussieht:

    "Kategorie" => ( 1 => 2)

    Insbesondere ist mir die innere map von int auf int nicht klar. Damit speicherst du eine Zuordnung von Zahlen auf Zahlen, also hier in deinem Beispiel von 1 auf 2. D.h. das "foo" wird nicht in der map gespeichert, sondern nur das Ergebnis von foo.



  • Ah ja, das macht natürlich Sinn. Danke für die Veranschaulichung!

    #include <map>
    #include <string>
    #include <iostream>
    
    int foo (int x, int y){
        return (x+y);
    }
    
    int main()
    {
        int y;
        std::cin >> y;
        std::map <std::string, int> test = {{"test", foo(1,2)-y}};
    
    }
    

    So ist es jetzt aber "Kategorie" => Rechnung - eingegebener Wert, richtig?



  • @Richard_Wunsch Jein.
    Jetzt ist es:
    "Kategorie" => Ergebnis
    Aus deinem Ergebnis kannst du aber natürlich nicht mehr ursprüngliche Eingabe und deine Formel ableiten. Ich weiß natürlich nicht, ob das dein Ziel ist.


Anmelden zum Antworten