Frage zu Strukturen und Funktionen



  • Hi.Ich habe vor ein kleines Periodensystem als DOS Anwendung zu programmieren.
    Sollte ja nicht gerade schwer sein.Die Elemente definiert man als Strukturen und eine Funktion gibt immer die Werte (Ordnungszahl,Masse,Schale,Hauptgruppe,usw...) von dem Element ein,das der User eingibt.
    Nur mein Problem ist.Wie setze ich es um,dass die Funktion weiß,was der User für ein Element eingegeben hat?
    Mein Ansatz wäre in etwa:

    void ausgeben(element auswahl)
    {
       cout <<auswahl.ordnungszahl<<auswahl.masse //usw...
    }
    int main()
    {
            ...
            string auswahl;
            cin >>auswahl;
    }
    

    Wenn ich es so mache,rechnet die funktion ausgeben aber natürlich nicht mit dem Wert von "auswahl"(beispielsweise "Wasserstoff",sondern mit dem Namen.
    Wie schaffe ich es,dass die Funktion den Wert von "auswahl" liest und nicht den Namen?
    Ich denke das lässt sich über Pointer machen,aber ich bin mir nicht sicher wie genau das aussehen müsste.
    Danke im Vorraus 🙂



  • Hi,

    Ich verstehe dein Problem nicht genau. Könntest Du vielleicht spezifizieren:
    a) Was der Benutzer genau eingeben soll?
    b) Was daraus in deinem Programm geschehen soll (Speicherung in Struktur, direkte Ausgabe)?
    c) Was Du mit Rechnen in diesem Zusammenhang meinst.



  • steht eigentlich in dem Post...
    Beispiel:

    1.Ich starte das Programm und werde aufgefordert ein Element einzugeben,über das ich mehr wissen will.
    2.Ich gebe "Wasserstoff" ein.
    Im Programm sind alle Elemente als Strukturen gespeichert.
    3.Die Funktion "ausgeben" führt ihre Anweisungen mit dem angegebenen Parameter.Also "Wasserstoff" aus.
    4.Auf dem Bildschirm erscheinen die chemischen Daten von dem Element Wasserstoff.

    Die Frage war :wie schaffe ich es,dass meine Funktion seine Anweisungen nicht mit dem Parameter "auswahl" ausführt,denn so heißt die eingegebene Variable,sondern ,wie oben beschrieben,mit dem Parameter "Wasserstoff",also dem Wert der Variablen.
    Hoffe das ist verständlich...



  • Achso, Du suchst nach einer einfachen Parameterübergabe.

    void ausgeben(const std::string& auswahl)
    {
        std::cout << /* ... */;
    }
    
    int main()
    {
        std::string eingabe;
        std::cin >> eingabe;
        ausgeben(eingabe);
    }
    

    Natürlich hat ausgeben jetzt erstmal nur den String. Aber die Frage, wie Du über string zu einer Struktur-Instanz kommst, kann man natürlich nur beantworten, wenn man weiß, wie diese gespeichert sind.

    Hilft Dir das?



  • Ganz einfach: du brauchst eine Funktion, die dem Namen "Wasserstoff" die Elemetinstanz zuordnet. Also sowas wie

    element get_element(string name)
    {
        // suche nach name in allen Elementen
    }
    
    ...
    
    ausgeben(get_element(auswahl));
    

    Möglich wäre auch eine einfach Map, bei der Funktion bist du aber flexibler bei verschiedenen Schreibweisen (wenn der Nutzer z.B. auch "H" eingeben darf).



  • Ich würde mir eine Klasse chemicalElements erstellen, diese hat eben die verschiedenen Datenmember wie Ordnungszahl, Hauptgruppe, Periode, Massenzahl, Elektronegativität und so weiter. Dann überladest du für diese Klasse den Ausgabeoperator. Du erstellst dann alle Elemente und wirfst sie zum Beispiel in eine Map

    std::map< chemicalElements, const std::string > elements
    

    Nun ließt du die Eingabe vom User ein und machst eine Funktion, die deine Map nach dem eingegebenen Element durchsucht. Ist dieses Element gefunden gibst du es mittels

    cout << wasserstoff
    

    aus( du musst natürlich wie gesagt den Ausgabeoperator überladen haben.

    Kannst es ja mal so versuchen, wenn du nicht weiter kommst melde dich einfach, dann wird dir sicherlich geholfen;-)( hatte aber jetzt echt keine Lust kurz den Code zu schreiben 😃 )

    Lg freeG



  • fr33g schrieb:

    Ich würde mir eine Klasse chemicalElements erstellen, diese hat eben die verschiedenen Datenmember wie Ordnungszahl, Hauptgruppe, Periode, Massenzahl, Elektronegativität und so weiter. Dann überladest du für diese Klasse den Ausgabeoperator. Du erstellst dann alle Elemente und wirfst sie zum Beispiel in eine Map

    std::map< chemicalElements, const std::string > elements
    

    Nun ließt du die Eingabe vom User ein und machst eine Funktion, die deine Map nach dem eingegebenen Element durchsucht. Ist dieses Element gefunden gibst du es mittels

    cout << wasserstoff
    

    aus( du musst natürlich wie gesagt den Ausgabeoperator überladen haben.

    Kannst es ja mal so versuchen, wenn du nicht weiter kommst melde dich einfach, dann wird dir sicherlich geholfen;-)( hatte aber jetzt echt keine Lust kurz den Code zu schreiben 😃 )

    Lg freeG

    So werde ich es mal versuchen.Habe zwar noch nie etwas von Maps gehört aber ich schau mal ob ich das hinkrieg.
    Danke für die schnellen Antworten,ich melde mich wieder,wenn ich es ausprobiert habe.



  • fr33g schrieb:

    std::map< chemicalElements, const std::string > elements
    

    Du meinst

    std::map<std::string, ChemicalElement> Elements;
    

    oder?



  • DocShoe schrieb:

    fr33g schrieb:

    std::map< chemicalElements, const std::string > elements
    

    Du meinst

    std::map<std::string, ChemicalElement> Elements;
    

    oder?

    Ja klar 😃 , sorry war mein Fehler, passiert mal eben so auf die schnelle 😉
    Danke für den Hinweis 🙂

    Lg freeG



  • Das "Ultra-Design" wäre natürlich ein Singleton mit mehreren Instanzen der Klasse (also allen verfügbaren Elementen), einer Zugriffsfunktion per String, die die deutsche Bezeichnung, die internationale Bezeichnung und das Elementsymbol durchsucht und, wenn verfügbar, die passende Instanz (sonst vielleicht eine Null-Instanz) zurückgibt, die man dann per Memberfunktion ausgeben kann oder ihre Informationen in einem String zusammengefasst bekommen kann, der dann ausgegeben werden kann. 😃



  • Ultra-Design und Singleton wirken geradezu parodisch, wenn man die parallele "Diskussion" in meinem Thread betrachtet (auch sonst). 😉



  • Kann mir mal jemand zeigen wie genau das mit der Map und dem Überladen in der Klasse funktionieren würde?Krieg das noch nicht so ganz hin.



  • fr33g schrieb:

    Ich würde mir eine Klasse chemicalElements erstellen, diese hat eben die verschiedenen Datenmember wie Ordnungszahl, Hauptgruppe, Periode, Massenzahl, Elektronegativität und so weiter. Dann überladest du für diese Klasse den Ausgabeoperator. Du erstellst dann alle Elemente und wirfst sie zum Beispiel in eine Map

    std::map< chemicalElements, const std::string > elements
    

    Nun ließt du die Eingabe vom User ein und machst eine Funktion, die deine Map nach dem eingegebenen Element durchsucht. Ist dieses Element gefunden gibst du es mittels

    cout << wasserstoff
    

    aus( du musst natürlich wie gesagt den Ausgabeoperator überladen haben.

    Ich würde das eher andersherum verwenden - der erste Template-Parameter von map<> ist der Suchschlüssel 😉

    @Babb: Wie weit bist du denn schon gekommen? Die Operator-Überladung brauchst du nicht unbedingt für den Anfang, da reicht es auch, eine Ausgabe-Methode für deine Klasse zu definieren.

    Zu der map:

    map<string,Element> Periodensystem;
    //Periodensystem füllen:
    Periodensystem["Wasserstoff"] = Element(1,"H",...);
    Periodensystem["Helium"]      = Element(2,"He",...);
    ...
    
    //Suchen und ausgeben
    cin>>name;
    map<string,Element>::iterator pos = Periodensystem.find(name);
    if(pos != Periodensystem.end())
      pos->print();
    else
      cout<<name<<" wurde noch nicht entdeckt"<<endl;
    


  • map<string,Element> Periodensystem; 
    //Periodensystem füllen: 
    Periodensystem["Wasserstoff"] = Element(1,"H",...); 
    Periodensystem["Helium"]      = Element(2,"He",...); 
    ... 
    
    //Suchen und ausgeben 
    cin>>name; 
    map<string,Element>::iterator pos = Periodensystem.find(name); 
    if(pos != Periodensystem.end()) 
      pos->print(); 
    else 
      cout<<name<<" wurde noch nicht entdeckt"<<endl;
    

    Und das soll einfach so in die Klasse? Ich nehm mal an,dass "Element"der Name der Struktur sein soll,in der die Elemente gespeichert sind und "Periodensystem" der Name der Map (oder meiner Klasse?) ist.

    Brauch ich (mehr als) den Header <map> ?Bisschen viele Fragen,ich weiß aber ich hab mich mit Maps noch nie auseinander gesetzt und auch mit Klassen habe ich in C++ noch nicht viel gearbeitet,also bin ich mit der Syntax kein bisschen vertraut.



  • Klar kannst du das alles in eine Klasse kapseln, in dem Fall solltest du die map<> selber eventuell umbenennen (und als privaten Member in die PeriodenSystem-Klasse packen). Der Code dort oben sollte nur demonstrieren, wie du die map verwenden kannst.



  • Ich geb dir mal ein Grundgerüst:

    ChemicalElement.h:

    #ifndef CHEMICAL_ELEMENT_H
    #define CHEMICAL_ELEMENT_H
    
    #include <string>
    
    class ChemicalElement
    {
        std::string international_name;
        std::string german_name;
        std::string element_symbol;
        int atomic_number;
        double element_weight;
    
        public:
        ChemicalElement(std::string const &p_international_name, std::string const &p_german_name, std::string const &p_element_symbol, int p_atomic_number, double p_element_weight);
        ChemicalElement();
        ~ChemicalElement(){}
    
        std::string GetInformationString();
    };
    
    #endif //CHEMICAL_ELEMENT_H
    

    ChemicalElement.cpp:

    #include "ChemicalElement.h"
    #include <map>
    #include <iostream>
    
    ChemicalElement::ChemicalElement(std::string const &p_international_name, std::string const &p_german_name, std::string const &p_element_symbol, int p_atomic_number, double p_element_weight)
      : international_name(p_international_name)
      , german_name(p_german_name)
      , element_symbol(p_element_symbol)
      , atomic_number(p_atomic_number)
      , element_weight(p_element_weight)
    {
    }
    
    ChemicalElement::ChemicalElement()
      : international_name("")
      , german_name("")
      , element_symbol("")
      , atomic_number(0)
      , element_weight(0.0)
    {
    }
    
    std::string ChemicalElement::GetInformationString()
    {
        //Hier die Informationen zusammenstellen und zurückgeben!
    }
    
    std::map<std::string, ChemicalElement> element_map;
    
    void init_element_map()
    {
        element_map["Wasserstoff"] = ChemicalElement("Wasserstoff", "Hydrogenium", "H", 1, 1.004);
        //andere Elemente hinzufügen
    }
    
    int main()
    {
        init_element_map();
    
        while(true)  //hier kann man natürlich noch eine "Nochmal?-Abfrage" einbauen
        {
            std::string element_name;
            //Element abfragen
    
            std::map<std::string, ChemicalElement>::iterator iter = element_map.find(element_name);
            if(iter == element_map.end())
            {
                std::cout << "Element existiert nicht!\n";
            }
            else
            {
                std::cout << iter->second.GetInformationString();
            }
        }
    }
    

    (OK, das ist jetzt noch nicht perfekt gekapselt, aber es zeigt dir schonmal die Syntax 😉 )



  • ChemicalElement();
    

    Ich mag diese Angewohnheit, Konstruktoren ohne sinnvolle Initialisierung einfach mal grundsätzlich anzubieten, nicht besonders. Hier ist halt etwas schade, dass man ohne Defaultkonstruktor den std::map::operator[] nicht mehr benutzen kann, dann müsste man eben zu insert() greifen.

    ~ChemicalElement(){}
    

    Wozu?

    std::string GetInformationString();
    

    Hier fehlt eine const -Qualifizierung.

    std::map<std::string, ChemicalElement> element_map;
    

    Würde ich eher lokal deklarieren und übergeben. Eventuell wäre typedef nicht schlecht.



  • @Nexus:
    Konstruktor - richtig, den habe ich erst nachher eingefügt, weil mir eingefallen ist, dass es sonst für Einsteiger noch komplizierter wird.
    Destruktor - Angewohnheit, den mit dazu zu schreiben
    const - richtig, vergessen, wenn auch hier nicht so wichtig
    typedef - mag ich in dem Fall nicht so (zumindest bei zweifacher Verwendung), Lokalisierung stimmt, ich habe ja gesagt, ich würde es am liebsten in einer Art Singleton machen, das wäre jetzt für den TE AFAIK aber zu kompliziert.



  • CStoll schrieb:

    fr33g schrieb:

    Ich würde mir eine Klasse chemicalElements erstellen, diese hat eben die verschiedenen Datenmember wie Ordnungszahl, Hauptgruppe, Periode, Massenzahl, Elektronegativität und so weiter. Dann überladest du für diese Klasse den Ausgabeoperator. Du erstellst dann alle Elemente und wirfst sie zum Beispiel in eine Map

    std::map< chemicalElements, const std::string > elements
    

    Nun ließt du die Eingabe vom User ein und machst eine Funktion, die deine Map nach dem eingegebenen Element durchsucht. Ist dieses Element gefunden gibst du es mittels

    cout << wasserstoff
    

    aus( du musst natürlich wie gesagt den Ausgabeoperator überladen haben.

    Ich würde das eher andersherum verwenden - der erste Template-Parameter von map<> ist der Suchschlüssel 😉

    fr33g schrieb:

    DocShoe schrieb:

    fr33g schrieb:

    std::map< chemicalElements, const std::string > elements
    

    Du meinst

    std::map<std::string, ChemicalElement> Elements;
    

    oder?

    Ja klar 😃 , sorry war mein Fehler, passiert mal eben so auf die schnelle 😉
    Danke für den Hinweis 🙂

    Lg freeG

    😉

    Lg freeG



  • Vielen Dank,wxSkip!
    Hat sehr geholfen die Syntax zu verstehen.Ich setz den Entwurf dann wohl morgen um.
    Vielen Dank an die vielen hilfreichen und extrem schnellen Antworten,nettes Forum 🙂


Anmelden zum Antworten