Mysteriöses Array Adressierungsproblem



  • und wann wird dann der Wert und wann die Adresse eines Arrayeintrages geändert?

    Wenn ich z.B. einen Arrayplatz mit dem Wert eines anderen Arrayplatzes beschreiben will ist das dann so richtig?

    a[1] = a[2];
    

    oder eher so:

    b = a[1];
    
    a[2] =b;
    

    oder besser gasagt was ist sicherer??



  • @ Dravere

    sorry aber was genau sind setter?


  • Administrator

    Wie bitte, du weisst nicht was ein Setter ist? Wahrscheinlich zu trivial, aber ok, hier ein Code:

    class CMyClass
    {
      // Attributes //
    private:
      int m_iAttribute;
    
      // Constructors & Destructor //
    public:
      CMyClass()
        : m_iAttribute(0)
      { }
    
      ~CMyClass() { };
    
      // Methods //
    public:
      void set_attribute(int iAttribute) { m_iAttribute = iAttribute; }; // Setter
      int get_attribute() const { return m_iAttribute; }; // Getter
    };
    

    Zu deinem zweiten Post, könntest du bitte noch die Typen angeben, das würde helfen, dir zu helfen 😉

    Grüssli



  • o.k. geschnallt du setzt die werte der Methodenattribute mit ner extra Funktion...mal sehen ob ich das noich einbaue - kostet mich wahrscheinlich nen Tag Arbeit den ganzen Code zu durchforsten..

    Mir geht's ganz Allgemein darum, wie ich es anstellen kann dass die Adresse eines Arrayplatzes z.B. a[2] bleibt wo sie ist und nur der Wert eines anderen Arrayplatzes übergeben wird.

    Wenn ich z.B. alle Werte eines Array um einen Arrayplatz verschieben will sodass dann am Ende

    a[i+1] = a[i]

    gilt...

    kann man das einfach so schreiben?

    Oder anders - wann wird eine Arrayadresse übergeben und wann der Wert??


  • Administrator

    Ich kann es nur nochmals fragen, von welchem Typ ist a? Denn das ist ganz entscheidend!

    int* a = new int[10];
    a[0] = a[1]; // Wert wird kopiert!
    
    int** b = new int*[10];
    
    for(int i = 0; i < 10; ++i)
    { b[i] = new int[2]; }
    
    b[0] = b[1]; // Zeiger wird kopiert. b[0] und b[1] Zeigen nun auf das gleiche Array!
    

    Grüssli



  • wieder schwierig...

    ich habe beispielsweise:

    struct bauteil { 
        double a;
        double b;
    };
    
    bauteil teil_1[10][100];
    
    teil_1[10][100].a = 5.12;
    
    teil_1[10][100].a = teil_1[0][0].a
    


  • wozu brauchst du denn jedes ma so riesen arrays?

    außerdem könntest du ma construktoren nutzen...

    und irgendwie hab ich auch den komischen verdacht, dass du der sprache nicht mächtig bist ><

    bb



  • free_style schrieb:

    wieder schwierig...

    ich habe beispielsweise:

    struct bauteil { 
        double a;
        double b;
    };
    
    bauteil teil_1[10][100];
    
    teil_1[10][100].a = 5.12;
    
    teil_1[10][100].a = teil_1[0][0].a
    

    Und was genau ist deine Frage?!



  • @unskilled:

    Vielen Dank für deine unqualifizierten und sehr Hilfreichen Beiträge!!

    wenn die Sprache denn soi einfach ist - wieso kann dann so ein Genie wie du meine Frage dann nicht sofort beantworten!!



  • @ drakon:

    genau das ist die Frage!

    wird bei jenem Codefragment der Wert oder die Adresse des Speicherplatzes des Array übergeben - ich war mir eigentlich sicher, dass ersteres der Falkl ist...nach auftauchen meines Problems bin ich mir da eben nicht mehr ganz so sicher wann ein Wert übergeben wird und wann ein Addresszeiger umgelegt wird.



  • free_style schrieb:

    bauteil teil_1[10][100];
    teil_1[10][100].a = 5.12;
    

    Dieser Code greift doch schon über die Array-Grenzen hinweg. Was danach passiert ist undefiniert. Im glücklichsten stürzt das Programm ab. Es können aber auch Kobolde aus der Nase fliegen.

    Riecht danach, dass du irgendwo über Array-Grenzen hinweg liest und schreibst.



  • Warum verwendest du z.B. ein zweidimensionales Array?

    Wenn es von der Logik her Sinn macht, kann man sowas auch so machen:

    struct Ttest
    {
        int *Array1;
        // hier noch andere Dinge reinschreiben, die zum Array gehören
    };
    
    Ttest *HauptArray;
    

    Um die ganze Konstruktion lässt doch dann auch noch prima eine Klasse basteln, mit Konstruktor, Destruktor, Getter, Setter...

    Das hilft jetzt zwar nicht wirklich weiter, aber ich wollte dir nur mal mit auf den Weg geben wie man solche Probleme, wie du sie gerade hast vermeidet. Nämlich durch ordentlich aufgebaute Datenstrukturen mit sicheren Zugriffsfunktionen.

    Also ein zweidimensionales Array würde ich nur dann nehmen wenn es sich wirklich um ein, in der Realität, 2-dimensionales Objekt handelt (Spielfeld, Schachbrett, etc... ). Gerade für Anfänger sind solche Dinger immer mit Fehlerquellen behaftet.



  • Es handelt sich sogar um ein dreidimensionales Objekt... 😉

    also konkret habe ich ein 2-D struct Array mit doubles, die die Variablen des Arrayplatzes speichert z.B.

    struct teil {
    
       double a;
       ...
    };
    
    struct teil teil_1[i][j];
    

    Müsste ich jetzt also für jede Variable eine Setter- und Getter-Funktion haben um das Ganze korrekt zu implementieren?

    so in etwa:

    struct teil {
    
       double a;
       ...
    
       void set_a (double z, int i, int j){
        teil.a[i][j] = z;   
       }
    
       double get_a(int i, int j){
         return teil[i][j].a
       }
    
    };
    

    sollte es damit dann keine Probleme mehr geben??



  • Nein es muss nicht sein, dass es dein Problem löst, aber es macht den Code übersichtlicher und leichter zu debuggen wie oben von anderen schon erwähnt.



  • free_style schrieb:

    struct teil
      {
       double a;
       ...
    
       void set_a (double z, int i, int j){
        teil.a[i][j] = z;   
       }
    
       double get_a(int i, int j){
         return teil[i][j].a
       }
    
    };
    

    =>

    struct teil
      {
       private:
         std::vector < std::vector <double> > a; //vll nen besseren Namen?
    /*falls du vector nicht benutzen willst, dann nimm double **a;
    aber ich würd hier auf jeden fall vector benutzen...*/
    
      public:
       void set_a (double z, int i, int j) //üblicherweise überlädt man dafür den operator []
       {
        teil.a[i][j] = z;   
       }
    
       double get_a (int i, int j) /*const*/
       { //operator []
         return teil[i][j].a
       }
    
    /*falls du vectoren nimmst, kannst du ja auch die .at () - Funktion von außen zugänglich machen
    und vor erst würd ich auch immer die nehmen - später kann man das immer noch ändern, wenn man weiß, dass die schleifen alle so stimmen
    und wenn der profiler sagt, dass es am at () hängt...*/
    
      teil (const size_t laenge_x, const size_t laenge_y); //todo...
    };
    

    Je nach Verwendung solltest du vll auch die reservere- und push_back-Funktion des Vektors zur Verfügung stellen... Du solltest halt nur darauf achten, dass die Dimensionen der Arrays nicht unterschiedlich sind...

    Also könntest du es auch so machen:

    struct teil
    {
    private:
      double a;
      double b;
    public:
      teil (double _a, double _b) : a (_a), b (_b);
      //todo: Getter + Setter für a und b
    };
    
    std::vector < std::vector <teil> > teile;
    /*wenn du die größe weist:*/
    teile.reserve (x);
    //todo:dann zum bsp. mit for_each die inneren vectoren...
    /*wenn nicht*/
    std::vector <teil> tmp (1, teil (dein_a, dein_b));
    /*oder*/
    std::vector <teil> tmp;
    while (/*abbruchbedingung*/)
    {
    //cin etc
    tmp.push_back (teil (tmp_a, tmp_b));
    };
    /*danach die neue Dimension anhängen:*/
    teile.push_back (tmp);
    

    nat. kannst du das ganze auch ganz bequem *hüstel* mit new und delete machen - oder lässt es so statisch, wie du hast - allerdings würd ich an deiner stelle std::vector nehmen - wenn du immer reserve aufrufst, sollte es auch genau so schnell sein, wie die statische c-variante...

    bb...



  • jaja ich machs jetzt richtig...seh ja ein dass die schnelle Variante nix bringt 😉

    Vielen Dank euch Allen für die Super Tips!! Habt mir sehr geholfen!!



  • unskilled schrieb:

    std::vector < std::vector <double> > a; //vll nen besseren Namen? 
    /*falls du vector nicht benutzen willst, dann nimm double **a; 
    aber ich würd hier auf jeden fall vector benutzen...*/
    

    Wenn man nur kleine Dimensionen und kleine Typen ( double ) hat, ist ein zweidimensionaler std::vector ja noch aktzeptabel. Man sollte sich dabei aber auch bewusst sein, dass der Container std::vector normalerweise mehr Speicherplatz reserviert als benötigt. Wenn seine Kapazität erreicht wird, reallokiert er sich mit doppelter Kapazität. In einem 2D-Vector quadriert sich das Ausmass der Speicherverschwendung, sodass es im Extremfall sogar sein kann, dass man nur einen Viertel des allokierten Speichers überhaupt nutzt. Bei grossen Objekten und Dimensionen kann das schon mal ein Problem werden. Ansonsten kann man die zweite Dimension auch in einem 1D-Vector darstellen und hat im Extremfall nur 50% Nutzung.



  • dafür gibt es ja reserve ^^

    unskilled schrieb:

    teile.reserve (x);
    //todo:dann zum bsp. mit for_each die inneren vectoren...

    wie würdest du es sonst machen, nexus?

    bb



  • unskilled schrieb:

    wie würdest du es sonst machen, nexus?

    Aus aktuellem Anlass habe ich mir diese Frage eben auch gestellt. Siehe dazu hier.

    Allerdings gings dort nicht genau um das wie hier, und ich will auch nicht behaupten, dass meine Lösung hierfür geeignet wäre. Ich habe jedoch eine eigene Containerklasse Table geschrieben, die nur soviel Speicherplatz belegt, wie sie benötigt. Weil Reallokationen in meinem Beispiel selten sind, halte ich das auch für legitim.

    Hier gehen Vektoren möglicherweise noch ohne Probleme (kommt wie gesagt auf Dimension und Objektgrösse drauf an), man sollte sich aber die Speicherverschwendung im Hinterkopf behalten. Und mit einer Abwälzung auf eine Dimension oder - wie du gesagt hast - mit reserve() kann man den Schaden immerhin schon geringer halten.


  • Administrator

    Wobei vielleicht noch drei Dinge zu beachten sind:
    1. Es wird nicht immer so Speicher allokiert, wie du es beschrieben hast, Nexus. Es gibt da ganz unterschiedliche Vorgehensweisen, teilweise sind sie noch schlimmer, teilweise weniger schlimm.
    2. Reserve garantiert nur, dass genügend Speicher vorhanden sein wird. Es heisst nicht, dass genau die Menge allokiert wird, welche übergeben wurde. Im allgemeinen wird mehr allokiert.
    3. Vielleicht könnte man die Alternativen zu std::vector benutzen? std::list? std::deque?

    Grüssli


Anmelden zum Antworten