array in struct zur laufzeit initialisieren



  • hi,

    ich habe ein kleines problem und zwar hab cih folgende struct

    struct ABC
    {
       int* array;
    };
    

    und möchte nun dem array erst beim erstellen einer neuen ABC Variable

    ABC* rb;
    

    die länge zuweisen.
    das hab cih so gemacht (funktioniert nicht - compiler sagt Segmentation fault, wenn ich auf ein array element zugreifen will):

    int capacity = 256;
    rb->array = new int [capacity];
    

    der zugriff sieht bei mir so aus:

    rb.array[255] = 2;
    

    Ich komm nicht auf den Fehler, danke für eure Hilfe schonmal



  • proty schrieb:

    hi,

    ich habe ein kleines problem und zwar hab cih folgende struct

    struct ABC
    {
       int* array;
    };
    

    und möchte nun dem array erst beim erstellen einer neuen ABC Variable

    ABC* rb;
    

    die länge zuweisen.

    Kleine Anmerkung: Ein Zeiger ist kein Array!

    das hab cih so gemacht (funktioniert nicht - compiler sagt Segmentation fault, wenn ich auf ein array element zugreifen will):

    int capacity = 256;
    rb->array = new int [capacity];
    

    der zugriff sieht bei mir so aus:

    rb.array[255] = 2;
    

    Hier kann ich keinen Fehler erkennen. Reduziere deinen Code solange, wie du den Fehler reproduzieren kannst. Wenn dann nicht zu viel Code übrig ist, kannst du diesen posten.


  • Mod

    Dazu sind Konstruktoren und Destruktoren gut:

    struct ABC
    {
       int* array;
       ABC(size_t size): array(new int[size]){}
       ~ABC(){delete[] array;}
    };
    

    Oder in praktisch jeder Hinsicht besser:

    struct ABC
    {
       std::vector<int> array;
       ABC(size_t size): array(size){}
    };
    


  • proty schrieb:

    hi,
    ...
    und möchte nun dem array erst beim erstellen einer neuen ABC Variable

    ABC* rb;
    

    die länge zuweisen.
    ...

    Du erzeugst aber kein Objekt sondern definierst nur einen pointer.
    Es müsste so heissen:

    ABC* rb = new ABC;
    


  • Danke fürs erste 🙂

    Ich hab jetzt:

    struct ABC
    {
       int* array;
       ABC(size_t size) : array(new int[size]) {}
       ~ABC() {delete[] array;}
    };
    

    und in der main will ich dann eine Variable vom Typ ABC anlegen:

    ABC* rb = new ABC(capacity);
    

    Das schluckt der compiler auch ohne fehlermeldung und ich kann wenn ich zb

    int capacity = 256
    

    setze auch auf die elemnte zugreifen aber wenn ich dann auf das 260 arrayelement zugriefen will kommt kein fehler, ist das array trotzdem von der richtigen länge?

    Danke nochmal 🙂



  • Außerdem machst du aus deinem Zeiger auf die Struktur plötzlich eine Instanz der Struktur.
    Mich wundert, dass das überhaupt kompiliert.

    rb->array[255] = 2;
    

    setze auch auf die elemnte zugreifen aber wenn ich dann auf das 260 arrayelement zugriefen will kommt kein fehler, ist das array trotzdem von der richtigen länge?

    Da kommt nur kein Fehler, weil keine Bereichsprüfung erfolgt. Das heißt aber nicht, dass dort nicht auch mal Informationen liegen können, die dein Programm zum Absturz bringen. Sprich das Verhalten ist nicht definiert und du solltest vorher prüfen, wie groß dein Array ist.



  • Ich hab jetzt eine Funktion zum erstellen einer neuen ABC instanz geschrieben, die sieht so aus:

    ABC create(int capacity)
    {
       ABC* rb = new ABC(capacity);  
       return *rb;
    }
    

    und in der main ruf ich das dann so auf:

    ABC rb = create(256);
    

    wenn ich dann

    for (int i = 0; i < MAX; ++i)
       {
          rb.array[i] = i+1;
          cout << rb.array[i] << endl;
       }
    

    schreibe, läuft das mit beliebigen werten für MAX (bzw. mit allen die ich getestet hab), das kann doch nciht stimmen oder?

    Sprich das Verhalten ist nicht definiert und du solltest vorher prüfen, wie groß dein Array ist.

    sizeof(rb.array) liefert im obigen beispiel 8...?



  • proty schrieb:

    Ich hab jetzt eine Funktion zum erstellen einer neuen ABC instanz geschrieben, die sieht so aus:

    ABC create(int capacity)
    {
       ABC* rb = new ABC(capacity);  
       return *rb;
    }
    

    Das ist ganz böse. Du erstellst im dynamischen Speicher ein Objekt, kopierst es und vergisst den Zeiger.

    proty schrieb:

    schreibe, läuft das mit beliebigen werten für MAX (bzw. mit allen die ich getestet hab), das kann doch nciht stimmen oder?

    Du schreibst einfach in Speicher der dir nicht gehört. Das geht solange gut, wie du nichts wichtiges überschreibst.

    proty schrieb:

    sizeof(rb.array) liefert im obigen beispiel 8...?

    Du hast ein 64Bit-System? Das ist die Größe des Zeigers. Die Größe eines dynamischen Arrays kannst du nicht mit sizeof() ermitteln, du musst dir immer die Größe merken.


  • Mod

    proty schrieb:

    Ich hab jetzt eine Funktion zum erstellen einer neuen ABC instanz geschrieben, die sieht so aus:

    ABC create(int capacity)
    {
       ABC* rb = new ABC(capacity);  
       return *rb;
    }
    

    und in der main ruf ich das dann so auf:

    ABC rb = create(256);
    

    LOL, wozu ist das denn gut? Einen Konstruktor in einer create Funktion kapseln?

    Mach doch einfach

    ABC rb(capacity);
    

    Dann bekommst du auch keine Probleme wegen dem fehlendem delete.

    schreibe, läuft das mit beliebigen werten für MAX (bzw. mit allen die ich getestet hab), das kann doch nciht stimmen oder?

    Kann schon sein, ist eben undefiniert. Wobei mich das schon wundert, dass du keinen Segfault bekommt. Hast du nie MAX>100000 probiert?

    Sprich das Verhalten ist nicht definiert und du solltest vorher prüfen, wie groß dein Array ist.

    sizeof(rb.array) liefert im obigen beispiel 8...?

    Klar, rb.array ist doch nur ein Pointer und 8 ist seine Größe. sizeof zählt schließlich nicht wie groß das ist, worauf der Pointer zeigt.

    Mach so etwas:

    struct ABC
    {
       int* array;
       size_t size;
       ABC(size_t size) : array(new int[size]), size(size) {}
       ~ABC() {delete[] array;}
    };
    

    Wobei dies darauf hinausläuft, dass wir jetzt nach und nach (den oben vorgeschlagenen) std::vector nachprogrammieren.



  • proty schrieb:

    Ich hab jetzt:

    struct ABC
    {
       int* array;
       ABC(size_t size) : array(new int[size]) {}
       ~ABC() {delete[] array;}
    };
    

    und in der main will ich dann eine Variable vom Typ ABC anlegen:

    ABC* rb = new ABC(capacity);
    

    🙄
    - Verletzung der Dreierregel bei struct ABC
    - Der Konstruktor sollte mit explicit versehen werden.
    - rb ist keine Variable vom Typ ABC. Es ist eine Variable vom Typ ABC*, also ein Zeiger.
    - Es gibt nur einen guten Grund, warum Du hier auf std::vector<> verzichten solltest: Zu Lernzwecken.
    - Es könnte soooooo einfach sein:

    struct ABC
    {
      std::vector<int> feld;
    
      explicit ABC(int groesse)
      : feld(groesse)
      {}
    };
    
    int main()
    {
      ABC obj (42);
      obj.feld[33] = 99;
      return obj.feld.size()==42 ? 0 : 1;
    }
    

    Man beachte die geringe Zahl an Sternchen in obigem Code: 0.

    Schreib nicht einfach irgend ein Zeug, ohne zu wissen, was da eigentlich passert. Lerne die Sprache richtig. Lies ein Buch dazu. etc etc etc


  • Mod

    krümelkacker schrieb:

    🙄
    - Verletzung der Dreierregel bei struct ABC

    Das musst du aber mir ankreiden, weil ich ihm das so vorgegeben habe. Ich wollte nicht zu viel auf einmal bringen, sondern erst einmal Konstruktoren zeigen (die er offensichtlich noch nicht kannte). Und ich hatte eigentlich erwartet, dass er gleich, wie von mir vorgeschlagen, einen vector nimmt, anstatt die Idee weiter zu verfolgen.



  • Okay danke, dann weiß ich was die größe angeht bescheid.

    Das ist ganz böse. Du erstellst im dynamischen Speicher ein Objekt, kopierst es und vergisst den Zeiger.

    Was meinst du damit?

    Ich hab die create funktion jetzt nochmal angepasst:

    ABC create(int capacity)
    {
       ABC rb(capacity);  
       return rb;
    }
    

  • Mod

    proty schrieb:

    Ich hab die create funktion jetzt nochmal angepasst:

    ABC create(int capacity)
    {
       ABC rb(capacity);  
       return rb;
    }
    

    Das ist prinzipiell ok, wenn man es richtig macht, aber:
    - Wozu soll das gut sein?
    - Wie krümelkacker schon sagte, habe ich in meinem Beitrag nicht alle nötigen Funktionen einer Klasse implementiert, die Daten dynamisch verwaltet. Unter anderem habe ich den Kopierkonstruktor weggelassen, daher ist das was hier geschieht nicht in Ordnung.

    Beantworte aber erst einmal die Fragen die dir hier im Thread gestellt wurden.



  • Es wurde ja schon darauf hingewiesen

    struct ABC
    {
       std::vector<int> values;
       ABC(size_t size): array(size){}
    }; 
    
    int main()
    {
      // ABC* abc = new ABC(256);
      // abc->values[260];
      // tu so
      ABC abc(256);
      abc.values.at(260); // jetzt sagt dir dein Programm auch, dass das nicht geht
      return 0;
    }
    

    edit: häm.. da hing ich wohl ein wenig zu lang in der Leitung...



  • - Wozu soll das gut sein?

    Ich will eine create funktion schreiben, da, wenn das mal richtig tut, weitere member in die struct kommen und die dann in der create funktion benutzt werden.

    wenn ich

    struct ABC
    {
       vector<int> array;
       ABC(size_t size): array(size){}
    };
    

    schreibe, sagt der compiler bei sowas

    rb.array[i]
    

    dass struct ABC kein meber array hat...?



  • proty schrieb:

    Das ist ganz böse. Du erstellst im dynamischen Speicher ein Objekt, kopierst es und vergisst den Zeiger.

    Was meinst du damit?

    Dass du das soeben dynamisch erstellte Objekt kopierst, wogegen nichts einzuwenden ist, aber dann den für das anschließende delete nötigen Zeiger dir nicht merkst. Du sollst nach Möglichkeit immer ein delete auf ein new folgen lassen. Nur in ganz wenigen Ausnahmefällen könnte man es aus Geschwindigkeitsgründen weg lassen.


  • Mod

    proty schrieb:

    - Wozu soll das gut sein?

    Ich will eine create funktion schreiben, da, wenn das mal richtig tut, weitere member in die struct kommen und die dann in der create funktion benutzt werden.

    Es kann Fälle geben, wo dies sinnvoll ist, aber ich gehe sehr stark davon aus, dass dies keiner davon ist.

    wenn ich

    struct ABC
    {
       vector<int> array;
       ABC(size_t size): array(size){}
    };
    

    schreibe, sagt der compiler bei sowas

    rb.array[i]
    

    dass struct ABC kein meber array hat...?

    Das sollte nicht sein. Gibt's andere Fehlermeldungen? Womöglich vector nicht eingebunden?



  • SeppJ schrieb:

    proty schrieb:

    - Wozu soll das gut sein?

    Ich will eine create funktion schreiben, da, wenn das mal richtig tut, weitere member in die struct kommen und die dann in der create funktion benutzt werden.

    Es kann Fälle geben, wo dies sinnvoll ist, aber ich gehe sehr stark davon aus, dass dies keiner davon ist.

    Gibts dann eine andere möglichkeit dem nicht vollständig definierten array im struct int array[] beim initialiseren einer neuen struct variable die länge zuzuweisen?

    wenn ich

    struct ABC
    {
       vector<int> array;
       ABC(size_t size): array(size){}
    };
    

    schreibe, sagt der compiler bei sowas

    rb.array[i]
    

    dass struct ABC kein meber array hat...?

    Das sollte nicht sein. Gibt's andere Fehlermeldungen? Womöglich vector nicht eingebunden?

    die fehlermeldung is

    error: invalid conversion from ‘int*’ to ‘long unsigned int’
    und
    error: initializing argument 1 of ‘std::vector<_Tp, _Alloc>::vector(size_t, const _Tp&, const _Alloc&) [with _Tp = int, _Alloc = std::allocator<int>]’



  • mein ganzer quellcode sieht so aus:

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    struct ABC
    {
       vector<int> array;
       ABC(size_t size) : array(new int[size]) {}
    
    };
    
    ABC create(int capacity)
    {
       ABC rb(capacity);
    
       return rb;
    }
    
    int main()
    {
       ABC rb = create(256);
       cout << sizeof(rb.array) << endl;
       for (int i = 0; i < 256; ++i)
       {
          rb.array[i] = i+1;
          cout << rb.array[i] << endl;
       }
       return 0;
    }
    


  • 🙂

    probiers mal mit:

    Zeile 9: ABC(size_t size) : array(size) {} // damit wird die Arraygröße zur Erstellungszeit festgelegt
    
    Zeile 23: cout << rb.array.size() << endl;
    

    Und bitte mach mal den Quatsch mit der create-Funktion weg.


Log in to reply