Datencontainer



  • Ich möcht eine folgende Struktur in einem Container abbilden:

    Es gibt mehrere LinienSegmente. Ein LinienSegment besteht aus mehreren Einzelpunkten, diese Einzelpunkte haben x- und Y Koordinaten und jedes LinienSegment besitzt 1 Label.

    Da ich noch nie mit Container in c++ geaebeitet habe, zunächst die Frage welcher Container sich anbietet.

    Und dann die Frage, wie ich den Bezug (Abhängigkeit) zwischen dem übergeordneten LinienSegment zu den Einzelpunkten und dann zu den dazugehörigen Koordinaten abbilde. Den Container brauche ich zum testen, daher möchte ich keine Klassen anlegen. Sondern den Container richtig aufbauen und mit dann Werte zum testen einlesen.

    freue mich über Hilfe, schon mal vielen Dank!



  • Meinst du das?

    #include <iostream>
    #include <vector>
    #include <string>
    
    using namespace std;
    
    struct TPunkt {
      double x;
      double y;
      TPunkt(const double _x, const double _y) {
        x = _x;
        y = _y;
      }
    };
    
    struct TLinienSegment {
      vector<TPunkt> Punkte;
      string label;
    };
    
    vector<TLinienSegment> Liniensegmente;
    
    int main() {
      //...
    
      //Liniensegmente füllen, meinetwegen so:
      TPunkt p1(100,100);
      TPunkt p2(200,100);
    
      TLinienSegment Liniea;
      Liniea.Punkte.push_back(p1);
      Liniea.Punkte.push_back(p2);
      Liniea.label = "meine Linie";
    
      Liniensegmente.push_back(liniea);
    
      // Zugriff dann auf den Container:
    
      for(int it=0;it!=Liniensegmente.size();++it) {
        for(int it2=0;it2!=Liniensegmente[it].Punkte.size();++it2)
          if(Liniensegmente[it].Punkte[it2].y==100)
            cout << "Punkt " << it2 << " des Liniensegments " << it << " hat die y-Koordinate 100" << endl;  
      }
      return 0;
    }
    


  • ja, passt genau!
    Vielen, vielen Dank!
    Bin Anfänger und dachte man braucht Klassen oder komplizierten Datencontainer.

    Danke für den Tip mit struct + Quellcode!

    Verstehe ich das richtig, dass man bei Referenzieren "." bei struct und "->" bei Klassen verwendet?



  • "." verwendest du auch bei Objekten, die du auf dem Stack anlegst.

    z. B.

    Object o = Object()
    o.myMethod()
    

    Die mußt/darfst du nicht mit delete löschen!!!



  • ups...

    und "->" bei struct auf dem Heap

    Also hängt es nur davon ab, ob das Objekt auf dem Heap (mit new) oder auf dem Stack (ohne new) ist...
    (Also eigentlich stimmt nicht 100%ig sollte aber erstmal reichen)



  • Bin selbst anfanger, soweit ich bisher bin folgendes:

    1.Klassen und structs sind ein und dasselbe AUSSER dass bei Klassen die Elemente automatisch private sind, bei structs hingegen public.

    2. du greifts immer mit . auf deine Elemente zu. Das Problem sind jetzt aber Pointer. Wenn du einen Pointer auf ein Objekt hast und nun ein Element dieses Objekts ansprechen wollen wuerdest waere es intuitiv *pobjekt.element zu schreiben. leider hat aber der . eine hoehere Prioritaet als das \*. Um also den Pointer zuerst zu dereferenzieren und DANN das Element anzusprechen muesstest du (*pobjekt).element schreiben. Tja, und die verkuerzte Schreibweise davon ist halt pobjekt->element

    Hoffe, dass das soweit alles korrekt und verstaendlich ist.



  • Infotyp schrieb:

    "." verwendest du auch bei Objekten, die du auf dem Stack anlegst....

    Infotyp schrieb:

    ups...

    und "->" bei struct auf dem Heap
    ..

    Ähhh ... das ist irgendwie "richtig gemeint", aber trotzdem nicht richtig.

    Viel einfacher:

    • "." bei Objekt(referenz)en
    • "->" bei Pointern

    Kleines Beispiel, warum die "Stack/Heap"-erklärung nicht greift:

    void callByVal(string s) { cout << s.length(); }
    void callByRef(string& s) { cout << s.length(); }
    void callByPtr(string* s) { cout << s->length(); }
    
    int main() {
        string stackStr;
        string *heapStr = new string;
        callbyVal(stackStr);
        callbyRef(stackStr);
        callbyPtr(&stackStr);
    
        callbyVal(*heapStr);
        callbyRef(*heapStr);
        callbyPtr(heapStr);
    
        delete heapStr;
        return 0;
    }
    

    😉

    BTW: IMO ist "->" ein überflüssiges syntaktisches Konstrukt (C-Altlast; der Compiler setzt das sowieso kontextbezogen um) .. was man ja offensichtlich bei Referenzen schon begriffen hat. 😃

    Gruß,

    Simon2.



  • Simon2 schrieb:

    BTW: IMO ist "->" ein überflüssiges syntaktisches Konstrukt (C-Altlast; der Compiler setzt das sowieso kontextbezogen um) .. was man ja offensichtlich bei Referenzen schon begriffen hat. 😃

    Altlast vielleicht, aber nicht überflüssig - schließlich ist es immer wieder notwendig, mit Pointern umzugehen - und p->x sieht eleganter aus als (*p).x . Und außerdem kannst du op-> auch überladen (z.B. für Smart-Pointer).



  • CStoll schrieb:

    ... p->x sieht eleganter aus als (*p).x ...

    Stimmt schon, aber warum nicht einfach p.x , wie bei Referenzen auch ?
    Ein nicht geringes Problem entsteht ja semantisch (z.B. bei operator-overloading) durch die Äquivalenz von "*." und "->" ... vom "Klammerwirrwarr" und den damit verbundenen Fehlern bei komplexeren Konstrukten noch gar nicht gesprochen ...

    Gruß,

    Simon2.



  • Wie kann ich etwas aus dem struct löschen? Ich wollte ein Liniensegment, hier Linie1 löschen

    #include <iostream>
    #include <vector>
    #include <string>
    
    using namespace std;
    
    struct TPunkt {
      double x;
      double y;
      TPunkt(const double _x, const double _y) {
        x = _x;
        y = _y;
      }
    };
    
    struct TLinienSegment {
      vector<TPunkt> Punkte;
      string label;
    };
    
    vector<TLinienSegment> Liniensegmente;
    
    int main() {
      //...
    
      //Liniensegmente füllen, meinetwegen so:
      TPunkt p1(100,100);
      TPunkt p2(200,100);
    
      TLinienSegment Liniea;
      Liniea.Punkte.push_back(p1);
      Liniea.Punkte.push_back(p2);
      Liniea.label = "meine Linie";
    
    TLinienSegment Linie1;
      Linie1.Punkte.push_back(p1);
      Linie1.Punkte.push_back(p2);
      Linie1.label = "Linie1";
    
      Liniensegmente.push_back(liniea);
    Liniensegmente.push_back(liniea);
    
    //remove Linienelement;
    delete [] Liniensegmente.linie1;
      Liniensegmente.linie1; = NULL; //Fehler
        return 0;
    }
    

    vielen Dank für Hilfe..



  • delete ist hier falsch. Zum löschen von Elementen aus einem vector kann man erase() verwenden. Wenn das Element am Ende des vectors ist auch pop_back(). Bei erase mußt du wissen, an welcher Position im vector sich dein element befindet;
    Bsp.

    Liniensegmente.push_back(liniea);
    Liniensegmente.push_back(liniea);
    // nun sind zwei TLinienSegment Objekte im vector
    // löschen des ersten
    Liniensegmente.erase(Liniensegmente.begin());
    // löschen des letzten
    Liniensegmente.pop_back();
    


  • sorry bin Anfänger..
    erase habe ich ausprobiert, ich kann aber nicht auf das i-te Element einer for-Schleife zugreifen.

    for (i = 0; i<v1.size(); i++) {
    	   startIterator = v1.begin();
    	   anzahl =0;
    	   for(int k=0;k<v1.size()&&anzahl<2;k++) 
    	   { 
    
    		   if(strcmp (v1[i]->mainIdent, v1[k]->mainIdent) == 0)++anzahl; 
    	   } 
    
    	   if (anzahl > 1  )  {
    
    		   v1.erase( startIterator +i ); //hier wird der falsche gelöscht
    		   //	v1[i]->mainIdent[0] = 0;  Ist der richtige, ist aber nicht gelöscht
    


  • <---> schrieb:

    sorry bin Anfänger..
    erase habe ich ausprobiert, ich kann aber nicht auf das i-te Element einer for-Schleife zugreifen.

    sicher geht das.

    <---> schrieb:

    for (i = 0; i<v1.size(); i++) {
    	   startIterator = v1.begin();
    	   anzahl =0;
    	   for(int k=0;k<v1.size()&&anzahl<2;k++) 
    	   { 
    		   
    		   if(strcmp (v1[i]->mainIdent, v1[k]->mainIdent) == 0)++anzahl; 
    	   } 
    	   
    	   if (anzahl > 1  )  {
    		   
    		   v1.erase( startIterator +i ); //hier wird der falsche gelöscht
    		   //	v1[i]->mainIdent[0] = 0;  Ist der richtige, ist aber nicht gelöscht
    

    .. nun Du löscht das i'te Element in 'vl'. D.h. nach dem Löschen ist das Element nicht mehr vorhanden.
    Was soll das Programm eigentlich tun? Wenn der Algorithmus dafür sorgen soll, dass da keine Kopien mehr in 'vl' vorkommen, so kannst Du den stl-algorithmus unique benutzen.
    Im Prinzip so:

    std::sort( vl.begin(), vl.end() );
    vl.erase( std::unique( vl.begin(). vl.end() ), vl.end() );
    

    Du benötigst aber noch einen Vergleichsoperator für den Element-Typ in 'vl'.

    Gruß
    Werner



  • Das Programm soll unter einer bestimmten Bedingung Elemente aus dem Vektor löschen. Da ich sicherstellen möchte, dass jedes Element mind 1 x vorkommt, steht in der if Anweisung anzahl >1. Vermutlich mache ich einen Fehler beim Zugriff auf das zu löschende Element. Denke der Iterator stimmt nicht, ich finde aber nicht wo. Wenn du es findest ist super, aber denke es ist schwierig zu finden, ohne zu debuggen. Meine Frage daher, bin ich auf dem richtigen Weg oder ist der Ansatz grundsätzlich falsch? Denn der Vector ist ja mit einer Struktur gefüllt.

    Und wenn ich nicht lösche, sondern das betreffende Element der Struktur auf 0 setze, wird das richtige ausgegeben. s.u. v1[i]->mainIdent[0] = 0;

    Von daher, kann man ein Vektorelement, das auf eine Struktur oder Klasse verweist überhaupt löschen?

    Vielen Dank für Antwort!!!

    for (i = 0; i<v1.size(); i++) {
           startIterator = v1.begin();
           anzahl =0;
           for(int k=0;k<v1.size()&&anzahl<2;k++) 
           { 
    
               if(strcmp (v1[i]->mainIdent, v1[k]->mainIdent) == 0)++anzahl; 
           } 
    
           if ( bedingung && anzahl > 1  )  {
    
               v1.erase( startIterator +i ); //hier wird der falsche gelöscht
    //    v1[i]->mainIdent[0] = 0;  löscht den Richtigen
    


  • <---> schrieb:

    Das Programm soll unter einer bestimmten Bedingung Elemente aus dem Vektor löschen. Da ich sicherstellen möchte, dass jedes Element mind 1 x vorkommt, steht in der if Anweisung anzahl >1.

    Du meinst 'höchstens einmal' - oder?

    <---> schrieb:

    Vermutlich mache ich einen Fehler beim Zugriff auf das zu löschende Element.

    Nein, ich glaube nicht, das Problem liegt woanders.

    <---> schrieb:

    Denke der Iterator stimmt nicht, ich finde aber nicht wo. Wenn du es findest ist super, aber denke es ist schwierig zu finden, ohne zu debuggen. Meine Frage daher, bin ich auf dem richtigen Weg oder ist der Ansatz grundsätzlich falsch? Denn der Vector ist ja mit einer Struktur gefüllt.

    Der vector ist mit mehreren Elementen einer Struktur gefüllt.

    <---> schrieb:

    Und wenn ich nicht lösche, sondern das betreffende Element der Struktur auf 0 setze, wird das richtige ausgegeben. s.u. v1[i]->mainIdent[0] = 0;

    Wenn ein Element im vector gelöscht worden ist, so existiert es nicht mehr. Es kann also auch nicht mehr ausgegeben werden; auch nicht mit einer '0'.

    <---> schrieb:

    Von daher, kann man ein Vektorelement, das auf eine Struktur oder Klasse verweist überhaupt löschen?

    Ich verstehe nicht was Du mit dieser Frage meinst. Ein Vektorelement verweist auf keine Struktur.

    <---> schrieb:

    v1.erase( startIterator +i ); //hier wird der falsche gelöscht
    //    v1[i]->mainIdent[0] = 0;  löscht den Richtigen
    

    korrekt wäre hier, den Index 'i' zu dekrementieren, da er bereits auf das nächste Element verweist. Alle Elemente, die hinter dem gelöschten stehen, sind nach dem Löschen um einen Index nach vorne gerutscht.

    Wie gibst Du den Vektor anschließend aus und wie viele Elemente besitzt er noch?

    Gruß
    Werner



  • Oh, da habe ich mich anscheinend unklar ausgedrückt.

    Ich möchte sicherstellen, dass nach dem Löschen von jedem Elementtyp noch eins da ist. Es muss also A, B, C mind 1 x vorhanden sein.

    z.B.
    v1[i]->mainIdent: A
    nächstes v1[i+1]->mainIdent: B
    v1[i+1]->mainIdent: B
    v1[i+1]->mainIdent: C
    v1[i+1]->mainIdent: B
    v1[i+1]->mainIdent: B
    v1[i+1]->mainIdent: A
    v1[i+1]->mainIdent: C

    Da ich das Löschen nicht hinbekommen habe, habe ich v1[i]->mainIdent[0] = 0; So konnte ich testen, was raus soll und welche angezeigt werden müssen. Das funktioniert auch richtig. Daher möchte ich das auf 0 setzen durch "tatsächliches" Löschen erseten.

    Mit Stuktur meine ich, dass v1[i+1]->mainIdent, entsprechend wie TLinienSegment Liniea;
    Liniea.Punkte.push_back(p1);
    aufgebaut ist.

    vector<TLinienSegment> Liniensegmente entspricht v1
    TLinienSegment Liniea;
    Liniea.label = "A"; Liniea.label entspricht mainIdent

    Ich hoffe, es ist nachvollziehbar

    nochmals vielen Dank!


Log in to reply