Initialisierung eines Array schlägt fehl



  • Hallo zusammen,
    nachdem ich aus einem anderen Thread eine Anleitung bekommen habe, habe ich mir nun ein Template gebastelt, dass ein Array erstellt und dieses gegebenfalls vergrößert (z.B. wenn auf ein Element zugegriffen wird, das es überhaupt nicht gibt). Außerdem wollte ich, dass alle ungebrauchten Elemente mit 0 initialisiert wird. Also wenn das Array vergrößert wird, dann werden alle neuen Elemente auf 0 gesetzt.

    So sieht das aus:

    DynArray(int size) { //Konstruktor des Templates DynArray
       str.len=size;
       str.array=new T[size];
       for (int i=0; i<size; i++)
        str.array[i]=0;
      }
    //--------------------------------
    void NewSize (unsigned int NewSize) { //Vergrößerung des Arrays
        T *temp=new T[str.len];
        for (int i=0; i<str.len; i++)
         temp[i]=str.array[i];
        delete [] str.array;
        str.array = new T[NewSize];
        for (int i=0; i<NewSize; i++) {
         str.array[i]=temp[i];
         if (i>str.len) str.array[i]=0; //alle neuen Elemente auf 0 setzen
        }
        str.len=NewSize;
        delete [] temp;
       }
    //--------------------------------
     T operator [] (unsigned int index) { //ein überladener Operator
       if(index > str.len) NewSize(index);
       return str.array[index];
      }
    

    Nun ist das Problem, das das mit der Initialisierung nicht so ganz klappt:

    int main()
    {
     DynArray <int> a1(10);
     a1.Insert(67,3); //Vergrößerung des Arrays
     cout << a1.Length() << endl; //Ausgabe der Arraygröße mit anderer Methode --> funktioniert
     int zahl=a1[75];
     cout << zahl;
    } /zahl müsste 0 sein --> ist sie aber nicht
    

    Die Variable "zahl" müsste 0 sein, doch kommen immer wirre Zahlen - so wenn das Element keinen Wert bekommen hat. Woran liegt das? Das Programm lässt sich kompilieren, d.h. es sind keine syntaktischen Fehler vorhanden.

    Wer weiß Rat?

    Vielen Dank für eure Hilfe
    lg, freakC++



  • Zeile 9 - temp wird mit alter Länge erzeugt
    Zeile 15 - temp wird mit neuer Länge befragt. rumms.

    Ausserdem - ich würde nie riskieren new [] mit der Möglichkeit [0] zu rufen.
    Vielleicht geht das ja gut, aber dem delete [] traue ich dann nicht mehr...


  • Mod

    Du fängst bei 0 an zu zählen.

    int zahl=a1[75];
    

    erzeugt bei dir ein 75 elementiges array von al[0] bis al[74]. al[75] selber liefert darum nur Mist zurück.

    Dir ist aber schon klar, dass du dir WIRKLICH DRINGEND mal die STL anschauen solltest? Du programmierst gerade mit großem Aufwand std::map<int, typename T> nach.



  • Kommt doch 'n bißchen was zusammen 😉



  • Hallo zusammen,
    vielen Dank für eure Antworten.

    @Bisty: So besser?

    for (int i=0; i<NewSize; i++) {
         if(i<=str.len) str.array[i]=temp[i];
         else str.array[i]=0;
        }
    

    @SeppJ: Siehst du es für sinnvoll an, dass ich das Template so erweiter, dass wenn ich beispielsweise a1[75] schreibe, ein Array von 76 Elementen angelet wird, damit ich genau diesen Fehler umgehen kann. Auf der anderen Seite würde das natürlich für Verwirrung sorgen, da dann etwas anderen ausgeführt wird, als das was der Benutzer möchte.

    Sobald ich mein neues Buch habe werde ich mich in die STL Libary einarbeiten. Außerdem ist es doch eine gute Übung für mich 😉

    Ich korrigiere nun mal ein bissl und werde mich dann melden, ob es geklappt hat. Aber noch eine andere Frage bezüglich dem überladenen Operator. Ich habe folgendes geschrieben:

    T operator [] (unsigned int index) {
       if(index > str.len) NewSize(index);
       return str.array[index];
      }
    

    Man kann aber auch das schreiben:

    T& operator [](unsigned index) {
            if(index > val.len) 
                NewSize(index);
            return val.array[index];
        }
    

    Da ich mich immer noch ein bisschen schwer mit der Zeigerarithmetik tue, wollte ich fragen, was es bringt, dass ich hier den Referenzoperator noch hinzufüge. Mit welcher Adresse wird da genau gearbeitet bzw welche Adresse wird zurückgegebn?

    Vielen Dank
    lg, freakC++


  • Mod

    freakC++ schrieb:

    @SeppJ: Siehst du es für sinnvoll an, dass ich das Template so erweiter, dass wenn ich beispielsweise a1[75] schreibe, ein Array von 76 Elementen angelet wird, damit ich genau diesen Fehler umgehen kann. Auf der anderen Seite würde das natürlich für Verwirrung sorgen, da dann etwas anderen ausgeführt wird, als das was der Benutzer möchte.

    Ich würde sagen, dass wenn der Benutzer a1[75] schreibt, er auch erwartet, dass dieses existiert. Normalerweise weiß auch jeder C/C++ Programmierer, dass das dann 76 Elemente bedeutet.

    Ich korrigiere nun mal ein bissl und werde mich dann melden, ob es geklappt hat. Aber noch eine andere Frage bezüglich dem überladenen Operator. Ich habe folgendes geschrieben:

    T operator [] (unsigned int index) {
       if(index > str.len) NewSize(index);
       return str.array[index];
      }
    

    Man kann aber auch das schreiben:

    T& operator [](unsigned index) {
            if(index > val.len) 
                NewSize(index);
            return val.array[index];
        }
    

    Da ich mich immer noch ein bisschen schwer mit der Zeigerarithmetik tue, wollte ich fragen, was es bringt, dass ich hier den Referenzoperator noch hinzufüge. Mit welcher Adresse wird da genau gearbeitet bzw welche Adresse wird zurückgegebn?

    Es wird dann eine Referenz auf val.array[index] zurückgegeben. Da dieses Objekt auch nach dem Verlassen der Methode existiert, kann man es ohne Probleme als Referenz (besser aber als const Referenz) zurückgeben. Auf die Weise spart man sich auch eine Kopieraktion.



  • Hallo,
    so, ich habe alles korrigiert und es funktionier. Doch ein (anderes) Problem bleibt. Ich möchte nämlich mit diesem Programm alle Teiler aller Zahlen eines Intervalls herausfinden. Ich gebe also z.B. 4 und 8 ein und das Programm sucht zu allen Zahlen zwischen 4 und 8 (inkl. 4 und 😎 alle Teiler heraus.

    Ich möchte jetzt in diesem sich selbst vergrößernden Array diese Teiler speichern. Für jede Zahl soll ein eigenes Array angelegt werden.

    Mein Problem ist, dass ich nicht weiß, wie ich bei jedem Schleifendurchgang eine neue Instanz erzeugen soll.

    DynArray a1;

    So erzeuge ich eine Instanz, doch wie kann ich in einer Schleife nun a1, a2.. erzeugen.Ich habe versucht die Adressen von den Instanzen in einem anderem Array zu speichern und alles aufn Heap zu legen, doch das funzt nicht.

    Kann mir da jemand helfen?

    Vielen Dank
    lg,freakC++



  • freakC++ schrieb:

    Hallo zusammen,
    vielen Dank für eure Antworten.

    @Bisty: So besser?

    for (int i=0; i<NewSize; i++) {
         if(i<=str.len) str.array[i]=temp[i];
         else str.array[i]=0;
        }
    

    snip

    if(i<=str.len) str.array[i]=temp[i];
    Nein, Du hast da noch dieses 'letztes-Element'-Verständnisproblem.
    Bei Gleichheit greift er auch noch mal zu, und pickt dann temp[str.len].
    Das ist die Dimension - und die ist tabu für den Zugriff!


  • Mod

    freakC++ schrieb:

    So erzeuge ich eine Instanz, doch wie kann ich in einer Schleife nun a1, a2.. erzeugen.Ich habe versucht die Adressen von den Instanzen in einem anderem Array zu speichern und alles aufn Heap zu legen, doch das funzt nicht.

    Da du dich ja so gegen die STL sperrst: Das ist schon der richtige Ansatz, was genau geht denn nicht?



  • Hallo,

    Da du dich ja so gegen die STL sperrst

    Ich sperre mich nicht gegen STL, doch möchte ich einfach das Programm so schreiben, da ich mich sowieso gerade mit dynamischen Arrays und Zeigern beschäftige und dies als eine gute Übung ansehe.
    Ich habe folgendes versucht:

    DynArray <int> a1(10) //Anlegen einer Instanz
    DynArray <int> *array //Zeiger auf array
    
    array=new DynArray[10]; //So deklariere ich ein "normales" dynamisches Array, doch bezweifel ich, dass es auch hier so funzt.
    

    Das funktioniert so nicht. Da ich gerade nicht an meinem PC sitze, kann ich leider keine Fehlermeldung posten (kommt später), doch allein die zweite Zeile sieht in diesem Fall nach einem Fehler aus, da ich keinen Konstruktor aufrufe und laut meines Templates wird damit schon ein Array erstellt.. hä 😕

    Ich würde mich nochmal um einen Beispielcode freuen, der mir weiter auf die Sprünge hilft.

    Vielen Dank
    lg, freakC++

    PS.: Bitte nehmt es mir nicht übel, dass ich STL nicht nutzen will, doch möchte ich es einfach so schaffen und somit die dynamische Speicherverwaltung etc. auszschöpfen!


  • Mod

    Ein allgemeines Beispiel:

    template<class T> class foo{
    private:
      T datamember;
    public:
      foo(T t): datamember(t){}
      T getData(){return datamember;}
    };
    
    int main(){
      foo<int> *array[10];
      for (int i=0; i<10; ++i){
        array[i]=new foo<int>(i);
      }
      for (int i=0; i<10; ++i){
        cout<< array[i]->getData() <<endl;
      }
    
    }
    


  • Hallo SeppJ und natürlich auch alle anderen,
    danke für dein allgemeines Beispiel. Es hat mir sehr geholfen, doch leider bleibt weiterhin ein Problem stehen. In deinem Array gibt es eine definierte Zahl, die die Anzahl der Arrays angibt. Ich bekomme diese Zahl jedoch erst zur Laufzeit. So sieht es bei mir momentan aus:

    DynArray<int> *sum[dif]; //Fehler
     for (int i=0;i<dif;i++)
      sum [i]= new DynArray <int> ();
    

    Die int-Variable "dif" sagt mir, wieviele Arrays benötigt werden, doch der Compiler möchte hier einen Konstantenausdruck. Kann man dieses Problem auch irgendwie lösen?

    Viele Danke für deine und eure Hilfe
    lg, freakC++


  • Mod

    freakC++ schrieb:

    Die int-Variable "dif" sagt mir, wieviele Arrays benötigt werden, doch der Compiler möchte hier einen Konstantenausdruck. Kann man dieses Problem auch irgendwie lösen?

    Dann muss das eben auch wieder dynamisch sein.



  • Hallo,
    mmh...müsste man dann mit doppelten Zeigern arbeiten? Gibt es da vielleicht auch so einen guten Beispielcode wie Du ihn in einem deiner letzte Posts gezeigt hast?

    vielen dank
    lg, freakC++


  • Mod

    freakC++ schrieb:

    Hallo,
    mmh...müsste man dann mit doppelten Zeigern arbeiten? Gibt es da vielleicht auch so einen guten Beispielcode wie Du ihn in einem deiner letzte Posts gezeigt hast?

    Klar:

    template<class T> class foo{
    private:
      T datamember;
    public:
      foo(T t): datamember(t){}
      T getData(){return datamember;}
    };
    
    int main(){
      int anzahl;
      cout<<"Anzahl Durchläufe?"<<endl;
      cin>>anzahl;
      foo<int> **array;
      array = new foo<int>*[anzahl];
      for (int i=0; i<anzahl; ++i){
        array[i]=new foo<int>(i);
      }
      for (int i=0; i<anzahl; ++i){
        cout<< array[i]->getData() <<endl;
      }
    }
    


  • Hallo,
    danke für die Antwort. Du warst schneller als ich, dennoch hier mein Beitrag, der sich jedoch noch nicht auf deine letzte Antwort bezieht, aber dennoch den Code enthält (bin selber drauf gekommen...).

    Ich habe noch ein bisschen herumprobiert und folgenden Code erstellt:

    DynArray <int> **sum;
     sum = new DynArray <int> *[10];
     &sum[1]->Length; //Zugriff???
    

    So kompiliert das Programm fehlerfrei, doch hatte ich zunächst beim Zugriff folgendes geschrieben:

    sum[1]->Length;
    

    Hier sagt mir der Compiler: Elementfunktion muß aufgerufen oder ihre Adresse übernommen werden

    Ich hab nur durchs Ausprobieren den &-Operator davor gestellt. Warum kompiliert das Programm jetzt?? Ich verstehe das nicht. Dennoch bringt mir das nichts, denn ich kann die Laenge keiner int-Variable zuweisen, obwohl die Methode Length einen einen int-Wert zurückgibt.

    int zahl=&sum[1]->Length; //Fehler
    

    Auch hier erscheint der Fehler "Elementfunktion muß aufgerufen oder ihre Adresse übernommen werden".

    Wie löse ich dieses Problem?

    Vielen Dank
    lg, freakC++



  • freakC++ schrieb:

    sum[1]->Length;
    

    Ich vermisse die runden Funktionsaufrufsklammern ame Ende.



  • freakC++ schrieb:

    Ich habe noch ein bisschen herumprobiert und folgenden Code erstellt:

    DynArray <int> **sum;
     sum = new DynArray <int> *[10];
     &sum[1]->Length; //Zugriff???
    

    So kompiliert das Programm fehlerfrei, doch hatte ich zunächst beim Zugriff folgendes geschrieben:

    WTF?!
    sum zeigt auf ein Array von 10 Zeigern, die nicht initialisiert wurden.

    Wozu hast Du Dir die Mühe gemacht, ein "DynArray" zu schreiben, wenn Du es nicht nutzt und wieder auf diesen Zeiger-Hickhack ausweichst?

    Probier mal:

    #include <map>
    using std::map;
    int main() {
      map<int,map<int,int> > dings;
      dings[23][42] = 99;
    }
    

    freakC++ schrieb:

    sum[1]->Length;
    

    Hier sagt mir der Compiler: Elementfunktion muß aufgerufen oder ihre Adresse übernommen werden

    Abgesehen davon, dass die Zeiger nicht initialisiert wurden -- warum hast Du überhaupt Doppel-Zeiger? -- habe ich keine Definition Deiner DynArray-Klasse gesehen und kann auch nicht sagen, was bei "->Length;" falsch läuft. Falls es eine Funktion sein soll, dann hast Du den "Funktions-Aufruf-Operator" vergessen: die Klammern ().

    freakC++ schrieb:

    Ich hab nur durchs Ausprobieren den &-Operator davor gestellt. Warum kompiliert das Programm jetzt?? Ich verstehe das nicht. Dennoch bringt mir das nichts, denn ich kann die Laenge keiner int-Variable zuweisen, obwohl die Methode Length einen einen int-Wert zurückgibt.

    Aha. Dann soll "Length" also eine Elementfunktion sein. Gut, dann hast du die Klammern () vergessen, wenn Du das Ding aufrufen willst. Du darfst es aber eh nicht aufrufen, weil die Zeiger nicht initialisiert wurden.

    Das & davor ist -- glaube ich -- keine legale C++ Syntax. Dein Compiler mag das akzeptieren und einen Elementfunktionszeiger zurückgeben, den man eigentlich sonst über &DynArray<int>::Length bekommt.

    Gruß,
    SP



  • Hallo zusammen,
    sorry, dass ich mich gestern nicht gemeldet habe, doch war ich gestern in England.... Verdammt...ich habe echt vergessen die einzelne Instanz zu initialisiern und ich wundere mich über so ein komisches Zeug, das da raus kommt. Naja, so hat es dann funkioniert:

    int dif;
    DynArray <int> **sum;
    sum = new DynArray <int> *[dif];
    for (int i=0; i<dif; i++)
     sum[i]= new DynArray <int> ();
    

    Es ist halt alles etwas verwirrend (ich weiß, STL wäre hier viel esser :D), da ich ein dynamisches Array erstelle, indem sich wiederum die Adresse eines Arrays befindet, das sich automatisch vergrößert (ich bin froh nicht der Computer sein zu müssen, der das alles koordiniert).

    Ich probiere das jetzt mal aus und wenn es nicht klappt, dann melde ich mich wieder.

    Vielen Dank für eure Hilfe
    lg, freakC++



  • Hallo,
    leider bleibt ein Fehler bestehen. Zunächst möchte ich jedoch die Funktionsweise des Programms noch mehr erläutern.

    Ich gebe zwei Zahlen ein, z.B. 5 und 10. Das Programm sucht nun für jede Zahl zwischen 5 und 10 (einschließlich 5 und 10) alle Teiler heraus und gibt sie aus. Das ist hört sich erstmal nicht so schwer an und ich habe das auch hinbekommen. Ich möchte nun, dass das Programm für jede Zahl ein Array anlegt und alle Teiler reinschreibt. In diesem Fall müssten also 6 Arrays erstellt werden (5,6,7,8,9,10). Eigentlich wird man hier denken: "Ein klarer Fall für std::vecor oder Ähnliches, doch möchte ich dieses Programm ohne die Hilfe der STL Libary erstellen. Fragt am besten nicht warum...ich habe nichts gegen STL, doch denke ich, dass es die perfekt Übung für mich ist.

    Das Programm ist noch lange nicht fertig, weswegen Variablenbezeichnungen und Struktur noch zu wünschen lassen. Ich werde mich darum bald kümmern. Nun aber zum Problem: Ich habe jetzt die Arrays erfolgreich initilisiert, doch schaffe ich es nicht, etwas in die Arrays zu schreiben. Hier noch mal
    der Ausschnitt des Templates, das ein vergrößerbares Array erstellt:

    template <typename T> class DynArray
    {
     public:
      DynArray() {  //Konstruktor 1
       str.len=0;
      }
      DynArray(int size) {  //Konstruktor 2
       str.len=size;
       str.array=new T[size];
       for (int i=0; i<size; i++)
        str.array[i]=0;
      }
      ~DynArray() {
       delete [] str.array;
      }
      int Length (void) {  //Methode zum Herausfinden der Arraygröße
       return str.len;
      }
      void NewSize (unsigned int NewSize) { //Vergrößern des Arrays
        T *temp=new T[str.len];
        for (int i=0; i<str.len; i++)
         temp[i]=str.array[i];
        delete [] str.array;
        str.array = new T[NewSize];
        for (int i=0; i<NewSize; i++) {
         if(i<=str.len) str.array[i]=temp[i];
         else str.array[i]=0;
        }
        str.len=NewSize;
        delete [] temp;
       }
      void Insert (unsigned int key, T value) {   //Einfügen von Werten in das Array
       if (key > str.len || str.len==0) NewSize(key);
       str.array[key]=value;
      }
    ...
     private:
      struct Ar {
       T *array;
       unsigned int len;
       } str;
    

    Hier nun das eigentliche Programm:

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
     //Eingabe von i und end. i ist die Startzahl und end die Endzahl
     ...
     arrc=0, p=0; //arrc=aktuelles Array, p=Element des aktuellen Arrays
     int dif=end-i+1;
     DynArray <int> **sum;
     sum = new DynArray <int> *[dif];
     for (int i=0; i<dif; i++)
      sum[i]= new DynArray <int> ();
    
     for (i;i<=end;i++)  //Die einzelnen Zahlen
     {
      sum[arrc]= new DynArray <int> (); //Bei neuer Zahl muss neues Array erstellt werden
      for (int k=1; k<=i;k++)  //k=potentieller Teiler
      {
       if(i%k==0) //Jede Zahl wird auf Teiler überprüft
       {
        sum[arrc]->Insert(p,k); //Fehler
        p++; //Bei neuem Teiler wird das Element erhöht
       }
      }
      arrc++; p=0; //arrc wird bei jeder neuen Zahl erhöht; neue Zahl -> neues Array
    }
    

    Ich arbeite mit einer IDE und hier öffnet sich nur ein CPU-Fenster,d.h. es gibt keine Fehlermeldung. Wenn ich auf meine Erfahrung schließe, dann passiert dass, wenn z.B. das Array gar nicht definiert ist, oder das Element
    nicht vorhanden ist bzw. das Array zu klein ist. Ich dachte, dass Template macht das alles, doch gibt es irgendwo noch einen Fehler.

    Könnt ihr mir helfen, den Fehler zu finden, denn dann wäre ich einen ganzen Schritt weiter.

    Vielen Dank
    lg, freakC++

    /Edit: WEnn ich folgendes schreibe:

    sum[arrc]->Insert(p,k); 
    sum[arrc]->Read(p);
    

    dann überprüfe ich, ob die Zahl an die richtige Stelle in das richtige Array geschriebenn wurde. Die Ausgaben stimmen immer, bis zu einem bestimmten Punkt, wenn das Programm abstürzt. Dieser Punkt hängt von der Anfangszahl bzw der Endzahl ab.


Anmelden zum Antworten