Probleme mit Sichtbarkeit von Variable und Array



  • Hallo zusammen,
    vielen Dank für eure Antworten, doch habe ich immer noch Probleme. Zunächst möchte ich genauer schildern, wie das Programm aufgebaut ist. Wie schon gesagt möchte ich zehn Instanzen einer Klasse erstellen. Die Adressen dieser Instanzen sind in einem Array gespeichert. So sehen Konstruktor und andere Methoden aus:

    CRechteck::CRechteck(float iLaengeSeiteA, float iLaengeSeiteB)
    {
     SetzeSeiten(iLaengeSeiteA, iLaengeSeiteB); 
    }
    //---------------------------------------------------------------------------
    void CRechteck::SetzeSeiten(float iLaengeSeiteA, float iLaengeSeiteB)
    {
     iSeiteA=iLaengeSeiteA;
     iSeiteB=iLaengeSeiteB;
    }
    //---------------------------------------------------------------------------
    float CRechteck::BerechneFlaechen()
    {
     return iSeiteA*iSeiteB;
    }
    //---------------------------------------------------------------------------
    

    Bei der Erstellung einer neuen Instanz werden die Seitenlänge als Parameter des KOnstruktors übergeben und somit gespeichert. Das sieht so aus:

    static int iElAr=0;
    float iSeiteA=StrToFloat(Edit1->Text);
    float iSeiteB=StrToFloat(Edit2->Text);
    arrListe[iElAr] = new CRechteck(iSeiteA, iSeiteB);
    

    Dabei wird die Variable iElAr bei jedem Aufruf um eins größer. Zum Schluss kann ich dann individuell jedes Rechteck aufrufen und den Flächeninhalt bekommen:

    int iAnzeige;
    iAnzeige=StrToFloat(Edit3->Text);
    float flat=arrListe[iAnzeige-1]->BerechneFlaechen();
    

    Ich wollte nun das statische Array dynamisch machen. Das hat den Vorteil, dass ich bei Beginn des Programms durch ein Eingabefenster die Größe des Array bestimmen kann beziehungsweise angeben kann, wieviele Rechtecke ich eingeben möchte. Und hier liegt, dass Problem. Ich habe sowieso das Array als Member von Form1. Bis jetzt sah es so aus:

    class TForm1 : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
       ...
    private:	// Anwender-Deklarationen
    public:    CRechteck *arrListe[10];      // Anwender-Deklarationen
            __fastcall TForm1(TComponent* Owner);
    };
    

    Wie man sieht ist die Größe vorgegeben. Ich habe versucht akaris Vorschlag zu verwirklichen, doch bin ich daran gescheitert:

    class TForm1 : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
       ...
    private:	// Anwender-Deklarationen
    public:    CRechteck *arrListe;      // Anwender-Deklarationen
            __fastcall TForm1(TComponent* Owner);
    };
    
    ....
    
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
     int zahl=StrToInt(Edit1->Text);
     arrListe=new CRechteck[zahl];
    }
    

    Hier kommt die Fehlermeldung["Standardkonstruktor zum Initialisieren des Arrayelements vom Typ 'CRechteck' nicht gefunden". Dieser Quelltext würde doch bedeutetn, dass ich ein Array vom Typ CRechteck erstelle.

    Ich möchte aber, dass ich ein beliebig großes Array erstelle in dem ich dann die Adressen der Instanzen speicher (so wie oben, nur halt dynamisch). Irgendwo muss ich dann ja auch solch eine Zeile einbringen:

    arrListe[iElAr] = new CRechteck(iSeiteA, iSeiteB);
    

    Wie würde das beim dynamischen Array aussehen (da die Parameter "iSeiteA, iSeiteB) sehr wichtig sind.

    So, das war mein kleiner Vortrag. Auch wenn die Vorgehensweise vielleicht schwachsinnig ist, möchte ich das Problem dennoch so lösen, da ich, als Anfänger, ja was lernen möchte!!

    Ich hoffe auf eure Hilfe.

    Vielen Dank
    lg, freakC++



  • In diesem Fall brauchst du ein Array von Zeigern auf CRechteck. Also:

    class TForm1 : public TForm
    {
    __published:    // Von der IDE verwaltete Komponenten
       ...
    private:    // Anwender-Deklarationen
    public:    CRechteck **arrListe;      // Anwender-Deklarationen
            __fastcall TForm1(TComponent* Owner);
    };
    
    ....
    
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
     int zahl=StrToInt(Edit1->Text);
     arrListe = new CRechteck*[zahl];
    }
    


  • Hallo

    Die Fehlermeldung kommt weil dein CRechteckt keinen parameterlosen Konstruktor hat.

    Wenn du wirklich ein rohes dynamisches Array von Zeigern auf dynamische Instanzen haben willst, dann must du mit Zeiger auf Zeigern arbeiten...

    // Deklaration, in deinem Fall im Header als Member von TForm1
    CRechteck** arrListe;
    
    // Erstellung des Arrays für eine gewisse Anzahl an Elementen
    int x = ...;
    arrListe = new (CRechteck*)[x];
    arrListe[0] = new CRechteck(a,b);
    
    // Zuerst die Elemente hinter den Zeigern selber löschen
    for (int y = 0; y < x; y++)
      delete arrListe[y];
    // Dann das Array
    delete[] arrListe;
    

    Wie du siehst hast du damit sehr viel Arbeit mit manueller Speicherverwaltung. Soetwas sollte man nur in absoluten Notfällen tun (Arbeit mit C-Schnittstellen aus DLLs). Das ganze würdest du dir mit std::vector ersparen.

    bis bald
    akari

    /Edit : Braunstein war schneller



  • Hallo zusammen,
    ich danke euch, akari und Braunstein. Nun klappt es! Doch bei akaris Version ist laut meinem Compiler ein Fehler, denn er mag die
    Klammern um CRechteck* überhaupt nicht.

    Da ich aber hier etwas lernen möchte, ist das Thema für mich noch nicht abgeschlossen. Da ich immernoch ein Anfänger bin, möchte
    ich nochmal nachfragen, was dieser Quelltext jetzt genau macht.

    Ich habe erst vor einier Zeit mit dem Thema Zeigern angefangen und habe folgendes im Kopf:

    Ein Zeiger ist eine Variabel, die die Adresse einer anderen Variabel beinhalet. Ich kann mittels des Zeigers auf auf die
    Ursprungsvariabel zugreifen und sie auch abändern.

    Nun würde ich gerne auch verstehen, was hier gemacht wird (Zeiger auf Zeiger...warum...hä...;))! könntet ihr mir das vielleicht
    erklären?

    Was bedeuten genau diese Zeilen, wenn man es für Laien ausdrückt:

    CRechteck **arrListe;
     ...
     arrListe = new CRechteck*[zahl];
     arrListe[0] = new CRechteck(4,4);
    

    Warum muss ich hier mit doppelten Zeigern arbeiten, warum muss ich "new CRechteck*[zahl]" schreiben und kann das Sternchen nicht
    weglassen? Warum benötige ich zwei new-Operatoren - weise ich zweimal manuell Speicher zu?

    Könnt ihr mir das erklären?

    Vielen Dank
    lg, freakC++



  • Hallo

    Nun würde ich gerne auch verstehen, was hier gemacht wird (Zeiger auf Zeiger...warum...hä...;))! könntet ihr mir das vielleicht
    erklären?

    Zeiger auf Zeiger ist das was der Compiler sieht und braucht. Du als Programmierer mußt zusätzlich aber immer noch wissen, was genau dieses Konstrukt darstellen soll. Ins unserem Fall soll es ein dynamisches Array von dynamischen Instanzen darstellen (Es gibt noch einige andere Datenstrukturen und Verwendungszwecke, die man mit dieser Syntax verarbeiten könnte).
    Das innere (die Datentypen definieren sich immer von außen nach innen) Sternchen sagt dem Compiler : Es geht um Zeiger auf TRecheck. Das äußere Sternchen sagt dem Compiler : Die Adresse des inneren Zeigers soll von einem zweitem, außenliegenden Zeiger als Wert gehalten werden.
    Für den nächsten Schritt brauchst du Zeigerarithmetik : Denn Speicheradressen sind auch nur int-Werte, mit denen man rechnen kann, vor allem +1 und -1. Und da einfache rohe Arrays ihre Elemente immer genau hintereinander ablegen, kannst du durch ein Array mit einem Zeiger iterieren :

    int Array[5];
    int* x = &(Array[0]); // Adresse des ersten Elements des Arrays
    x++; // Zeiger zeigt nun auf die Adresse des zweiten Elements
    

    Der Umkehrschluß ist nun : Du kannst einen Zeiger benutzen, um ein Array vorzutäuschen. Darauf baut nun der äußere Zeiger. Der äußere Zeiger soll immer auf das erste Element unseres dynamisch angelegten Arrays von Speicheradressen sein. Es gibt also einen geschlossenen Speicherbereich im Heap, in dem hintereinander weg andere Speicheradressen stehen. Durch diese Adressen kann man nun mit dem dem []-Operator iterieren (muß aber immer die Gesamtanzahl an Elementen wissen, das dynamische Array weiß es nicht mehr).
    In dem Array liegen nun die Adressen der TRechteck-Instanzen, die du zusätzlich und an und für sich unabhängig vom Array noch im Heap angelegt hast, und können als Zeiger benutzt werden.

    kann das Sternchen nicht weglassen?

    Nein, denn du willst ja nicht ein Array von TRechteck-Instanzen erstellen (diese Variante haben ja wir vorgeschlagen, wolltest du nicht). Sondern ein Array von Zeigern auf TRechteck-Instanzen.

    Warum benötige ich zwei new-Operatoren - weise ich zweimal manuell Speicher zu?

    Du must einmal Speicher anfordern für das Array selber, und einmal für jede TRechteck-Instanz die von dem Array verwendet werden soll. Beachte dazu auch meine delete-Anweisungen, die Schleife dort brauchst du für ein komplettes Aufräumen.

    bis bald
    akari



  • Das ganze wird etwas einfacher wenn man, wie schon vorgeschlagen, statt dem Array std::vector verwendet.

    // Deklaration, in deinem Fall im Header als Member von TForm1
    std::vector<CRechteck*> arrListe;
    
    // Hinzufügen eines Rechtecks
    arrListe.push_back(new CRechteck(a,b));
    
    // Zuerst die Elemente hinter den Zeigern selber löschen
    for (int y = 0; y < x; y++)
      delete arrListe[y];
    // der vector selbst muss nicht gelöscht werden
    

    Jetzt kann man auch noch auf die zeiger verzichten. Dann sieht das so aus:

    // Deklaration, in deinem Fall im Header als Member von TForm1
    std::vector<CRechteck> arrListe;
    
    // Hinzufügen eines Rechtecks
    arrListe.push_back(CRechteck(a,b)); // kein new mehr
    
    // löschen entfällt hier ganz, das wird von vector selbst übernommen
    


  • Hallo zusammen,
    vielen Dank für deine Erklärung, akari und vielen Dank für deinen (wohl besseren) Lösungsvorschlag, Braunstein. Doch habe ich noch ein paar Fragen zu akaris Erklärungversuch.

    Das innere Sternchen sagt dem Compiler: Es geht um Zeiger auf TRechteck. Das äußere Sternchen sagt dem Compiler: Die Adresse des inneren Zeigers soll von einem zweite, außenliegendem Zeiger als Wert gehalten werden.

    1.) Der innere Zeiger ist der rechte Zeiger?
    2.) Beudeutet dies, dass ich hier zwei Zeiger vereinbare? Dazu habe ich dann eine Frage. Wenn ich einen Zeiger vereinbare,
    dann brauche ich ein Sternchen und kann dann auf diesen zugreifen:

    int *zeiger; //Ein Zeiger = ein Sternchen
    int zahl=4;
    zeiger=&zahl;
    *zeiger=10;  //Ich kann auf den einen Zeiger zugreifen
    ShowMessage(String(zahl));
    

    Ich habe hier den Wert einer Variablen über einen Zeiger verändert. Wenn ich nun zwei Sternchen schreibe, dann bedeutet das auch, dass ich zwei Zeiger habe. Doch wie greife ich auf den zweiten Zeiger zu (ich habe ja nur einen Variablennamen) und wie greife ich auf den ersten zu? Ich habe folgendes probiert:

    int **zeiger; //Ein Zeiger(name) = zwei Sternchen?
    int zahl=4;
    *zeiger=&zahl;//Ist das richtig?
    

    Wenn ich nun zwei Sternchen schreibe, wie kann ich auf beide Zeiger zugreifen. Der zuletzt gepostete Quelltext wird fehlerfrei compiliert, doch hagelt es während der Laufzeit Laufzeitfehler. Warum?

    Bedeutet das nun, dass ich einen Zeiger habe (hier "zeiger" genannt) und einen weiteren Zeiger (anscheinend kein Name), der auf "zeiger" zeigt. 😉
    Wie müsste das Programm dann heißen, damit es dasgleiche wie das obere macht?

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



  • Hallo

    freakC++ schrieb:

    Hallo zusammen,
    1.) Der innere Zeiger ist der rechte Zeiger?

    Nein, die Reihenfolge von innen nach außen wird von links nach rechts gelesen. Mal ein extremes Beispiel :

    int *const* x;
    // Bedeutet :
    // 1. int 
    // 2. *     -> Zeiger auf int
    // 3. const -> Konstanter Zeiger auf int (int-Wert kann verändert werden, der 
    //             Zeiger kann aber auf kein anderes int Zeigen)
    // 4. *     -> Variabler Zeiger auf einen konstanten Zeiger auf variables int
    
    int **zeiger; //Ein Zeiger(name) = zwei Sternchen?
    int zahl=4;
    *zeiger=&zahl;//Ist das richtig?
    

    Wenn ich nun zwei Sternchen schreibe, wie kann ich auf beide Zeiger zugreifen. Der zuletzt gepostete Quelltext wird fehlerfrei compiliert, doch hagelt es während der Laufzeit Laufzeitfehler. Warum?

    Dein zweifacher Zeiger sagt dem Compiler folgendes : Es gibt eine Speicherstelle, an der die Adresse einer anderen Speicherstelle steht (erstes Sternchen). An dieser zweiten Speicherstelle steht wiederrum eine Adresse einer dritten Speicherstelle (zweites Sternchen), und in dieser steht endlich der eigentliche int-Wert.
    In deinem Beispiel willst du nun zwar der zweiten Speicherstelle eine gültige Adresse zuweisen, hast aber vergessen zuerstmal dem ersten Zeiger eine gültige Adresse für die zweite Speicherstelle zuzuweisen. Das ist undefiniertes Verhalten (bei mirläuft der Code sogar ohne Fehlermeldung).

    Wie müsste das Programm dann heißen, damit es dasgleiche wie das obere macht?

    int **zeiger;
    int *buf; // Wird nur gebraucht, um den zweiten Zeiger einen gütigen Bereich zu verschaffen
    zeiger = &buf; // Erster Zeiger gesetzt
    int zahl=4;
    *zeiger=&zahl;// Zweiter Zeiger gesetzt
    buf=&zahl; // Alternativ : Zweiter Zeiger gesetzt
    std::cout << **zeiger << std::endl; // Korrekt
    

    Irgendwann wurde mal hier im Forum ein Video gepostet, das unterhaltsam grundlegende Zeigerarbeit erklärt... finds aber nicht mehr.

    bis bald
    akari



  • akari schrieb:

    Irgendwann wurde mal hier im Forum ein Video gepostet, das unterhaltsam grundlegende Zeigerarbeit erklärt... finds aber nicht mehr.

    Ich nehme an, Du meinst
    http://cslibrary.stanford.edu/104/



  • Hallo

    Ja genau, danke volkard.

    bis bald
    akari



  • Hallo Leute,

    ich finde das sehr interessant hier und lese fleissig mit 🙂

    mit anderen Worten:

    int **pointer;         // Zeiger auf einen int-Zeiger (eine Speicheradresse die auf eine Speicheradresse zeigt die auf einen int-Wert zeigt)
    int *buf;              // ein Zeiger auf einen int-Wert
    pointer= &buf;         // Zeiger auf int-Zeiger bekommt eine gültige Adresse zugewiesen (nämlich die Adresse des int-Zeigers)
    int zahl= 4;           // ein int-Wert wird im Speicher abgelegt
    *pointer= &zahl;       // der Zeiger buf bekommt die Adresse des int-Wertes zugewiesen (in pointer steht die Adresse des Zeiger buf, welche durch die Dereferenzierung das Zuweisungsziel für die Adresse des int-Wertes darstellt)
    buf= &zahl;            // dasselbe wie die Zeile darüber, nur anders ausgedrückt
    std::cout << **pointer << std::endl; // dereferenziert den Zeiger pointer und den Zeiger buf, wodurch der int-Wert ausgegeben wird
    std::cout << *buf << std::endl;      // dasselbe wie die Zeile darüber, nur anders ausgedrückt
    

    richtig?

    auf das Rechteck-Beispiel bezogen:

    CRechteck** arrListe;                // member-Variable: Zeiger auf einen Rechteck-Zeiger
    
    int x= ...;                          // ein int-Wert, welcher die Anzahl der Feld-(Array-)Elemente enthält
    arrListe = new (CRechteck*)[x];      // Zeiger auf Rechteck-Zeiger erhält die Startadresse eines Array von Rechteck-Zeigern
    arrListe[0] = new CRechteck(a,b);    // dem ersten Element des Zeigerarray wird die Adresse einer konkreten Rechteck-Instanz zugewiesen
    
    // löschen:
    for(int y= 0; y < x; y++)
        delete arrListe[y];              // die einzelnen Instanzen auf welche die Zeiger des Zeigerarray zeigen werden gelöscht
    delete[] arrListe;                   // der Zeiger auf den 1. Rechteck-Zeiger wird gelöscht
    


  • Hallo

    @ Kolumbus : Ja, richtig

    Edit : Zu meinem zweiten Beispiel noch zwei Anmerkungen :
    - Wie schon erwähnt müßen die runden Klammern beim ersten new weg.
    - Das zweite new müßte eigentlich auch in einer Schleife abgehandelt werden,
    denn man braucht x Instanzen von CRechteck.

    bis bald
    akari



  • Folglich (etwas modifiziertes Beispiel, damit es nicht so langweilig ist):

    CRechteck** arrListe;                      // member-Variable: Zeiger auf einen Rechteck-Zeiger
    
    // erstellen:
    int a= 2, b= 3, x= 10;                    // a, b: Seitenlängen der Rechtecke | x: ein int-Wert, welcher die Anzahl der Feld-(Array-)Elemente enthält (hier 10)
    arrListe = new CRechteck*[x];             // Zeiger auf Rechteck-Zeiger erhält die Startadresse eines Array von 10 Rechteck-Zeigern
    for(int y= 0; y < x; y++)
        arrListe[y] = new CRechteck(a++,b++); // den Elementen des Zeigerarray wird die Adresse von konkreten Rechteck-Instanzen zugewiesen
                                              // die Seitenlängen werden bei jedem Durchgang um 1 erhöht
    
    // Zugriff:
    int FlaecheninhaltB= (*arrListe[1].Width) * (*arrListe[1].Height); // Flächeninhalt des 2. Rechteckes (ist 12) so ermittelbar???
    
    // löschen:
    for(int y= 0; y < 10; y++)
        delete arrListe[y];                   // die einzelnen Instanzen auf welche die Zeiger des Zeigerarray zeigen werden gelöscht
    delete[] arrListe;                        // der Zeiger auf den 1. Rechteck-Zeiger wird gelöscht
    

    Ist das mit dem Zugriff so richtig? Ich denke mir das so: arrListe[1] enthält die Adresse der 2. Rechteck-Instanz, die ich mit *arrListe[1] erhalte...!?!



  • Hallo

    Nicht ganz. Um von arrListe auf Width und Height zuzugreifen must schreiben :

    (*arrListe[1]).Width // beachte die versetzte schließende Klammer
    // oder
    arrListe[1]->Width
    

    bis bald
    akari



  • Ok, danke - verstanden soweit (auch wenn ich's aktuell nicht brauche). 👍

    Vielleicht hilfts ja freakC++ ein wenig beim Verständnis...



  • Hallo zusammen,
    vielen Dank für eure Antworten. Sie haben mir sehr geholfen und ich bin schon um einiges weiter. Ich sitze nämlich gerade hier in Frankreich in unserem Ferienhaus, schaue auf die Kuhweide und bringe mir weiter C++ bei ;). Dabei noch eure Hilfe....besser gehts nicht!!!

    So, noch ein paar letzte Fragen.

    1.) Kann man die Variable "buf" als eine Art Brücke ansehen ohne welche nicht auf weiter hinten stehende Variablen zugegriffen werden kann?

    2.) Kann man als Schema folgendes schreiben:

    int **zeiger;
    // Pointer -> Pointer1 -> Variable
    

    Bei mir war doch das Problem, dass ich zwar Pointer2 eine Adresse zugewiesen habe, doch Pointer1 ging leer aus? Ich habe also nicht ausreichend dereferenziert!?

    3.) Um jetzt auf das Rechteckbeispiel nochmal zu kommen:

    CRechteck **arrListe;
    
    /*Ich erstelle einen Zeiger, der die Adresse eines anderen Zeigers enthält, wobei diese auf eine Variable vom Typ CRechteck zeigt?
    
    arrListe --> arrListe1 --> Variable des Typs CRechteck*/
    
    arrListe = new CRechteck *[zahl];
    
    /*Ich weise dem ersten Pointer Speicherplatz zu?? Hier bin ich mir nicht sicher, obwohl Kolumbus ja schon etwas geschrieben hat. Könnt ihr nochmal genau sagen (so einfach wie möglich ;)), was hier genau passiert. Vielleicht könnt ihr euch ja auf akaris letztes Beispiel beziehen, denn ich denke, dass dies relativ ähnlich ist.*/
    
    arrListe[0]=new CRechteck (4,4);
    
    /*ich weise der ersten Instanz von CRechteck Speicherplatz zu und übergeben zwei Zahlen an den Konstruktor.*/
    

    Warum muss ich hier nie vor arrListe ein Sternchen schreiben. Es ist doch eigentlich das gleiche wie mit **zeiger und da musste ich in einem Schritt auch *zeiger schreiben. Vorallem der zweite Quelltext ist mir wichtig, da dieser mir momentan noch Kopfschmerzen bereitet. Warum steht das Sternchen genau vor [zahl].

    Vielen Dank für eure Hilfe, denn ich bin schon sehr viel weiter!

    lg, freakC++



  • freakC++ schrieb:

    Hallo zusammen,
    vielen Dank für eure Antworten. Sie haben mir sehr geholfen und ich bin schon um einiges weiter. Ich sitze nämlich gerade hier in Frankreich in unserem Ferienhaus, schaue auf die Kuhweide und bringe mir weiter C++ bei ;).

    👍

    freakC++ schrieb:

    1.) Kann man die Variable "buf" als eine Art Brücke ansehen ohne welche nicht auf weiter hinten stehende Variablen zugegriffen werden kann?

    Kann man so ansehen. Du hast einen Zeiger pointer der auf buf zeigt und eine Variable (Speicherbereich) x auf die noch nichts zeigt. Wenn du buf jetzt nicht die Adresse von x gibst, kannst du mit pointer auch nix anfangen.

    freakC++ schrieb:

    2.) Kann man als Schema folgendes schreiben:

    int **zeiger;
    // Pointer -> Pointer1 -> Variable
    

    Bei mir war doch das Problem, dass ich zwar Pointer2 eine Adresse zugewiesen habe, doch Pointer1 ging leer aus? Ich habe also nicht ausreichend dereferenziert!?

    Das könnte man als abstraktes Schema so schreiben.
    Genau, bei dir wurde Pointer1 nicht mit einer Adresse initialisiert.
    Dereferenzieren bedeutet, dass du nicht den Wert der Zeiger-Variablen meinst, sondern das, was an der Adresse steht die in der Zeiger-Variablen gespeichert ist. 😉
    Beispiel:

    int *Zeiger;
    int IntVariable;
    Zeiger= &IntVariable; // bedeutet die Speicheradresse von IntVariable wird im Zeiger gespeichert, egal was für einen Wert IntVariable hat
    *Zeiger= 3;           // <== Dereferenzieren: du weist nicht dem Zeiger die 3 zu, sondern IntVariable (also speicherst du eine 3 an der Speicherstelle, welche von IntVariable belegt ist)
    

    Das wiederum sollte jedoch in jedem Grundlagenbuch erklärt sein (dereferenzieren).

    freakC++ schrieb:

    3.) Um jetzt auf das Rechteckbeispiel nochmal zu kommen:

    CRechteck **arrListe;
    
    /*Ich erstelle einen Zeiger, der die Adresse eines anderen Zeigers enthält, wobei diese auf eine Variable vom Typ CRechteck zeigt?
    
    arrListe --> arrListe1 --> Variable des Typs CRechteck*/
    

    Beachte die Formulierung: Du erstellst einen Zeiger, der auf die Adresse eines anderen Zeigers zeigen kann! Der Zeiger kann auf etwas zeigen, tut es aber konkret noch nicht! Ansonsten richtig.

    freakC++ schrieb:

    arrListe = new CRechteck *[zahl];
    
    /*Ich weise dem ersten Pointer Speicherplatz zu?? Hier bin ich mir nicht sicher, obwohl Kolumbus ja schon etwas geschrieben hat. Könnt ihr nochmal genau sagen (so einfach wie möglich ;)), was hier genau passiert. Vielleicht könnt ihr euch ja auf akaris letztes Beispiel beziehen, denn ich denke, dass dies relativ ähnlich ist.*/
    

    Ja, du sagst dem 1. Pointer er soll auf die Startadresse eines Array mit <zahl> Elementen zeigen. Das Array ist vom Typ Zeiger auf CRechteck (wie es auch Arrays vom Typ char gibt). Das Array wird in dieser Zeile auch gleich im Speicher angelegt (durch das new).

    Muss erstma aufhören... Rest später 😉



  • Hallo,
    ok dann warte ich auf deine Fortsetzung. Zwischen durch noch das (ich habe etwas Neues ausprobiert):

    int **zeiger;
     int zahl=4;
     *zeiger=&zahl;
     zeiger=&(*zeiger); //Warum geht das nicht
     ShowMessage(String(**zeiger));
    

    Wieder kommt ein Laufzeitfehler, doch dachte ich, dass ich hier nun auch Pointer1 und Pointer2 eine Adresse zugewiesen habe! Ich habe versucht auf die Variable "buf" zu versichten

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



  • Hallo

    Bis zur dritten Zeile hast du nichts verändert, deshalb kommt der gleiche Fehler wie vorher. Vor dem Verwenden von *zeiger must du zeiger erstmal eine gülige Speicheradresse zuweisen! Und daran krankt auch das hier :

    zeiger=&(*zeiger);
    

    Denn bevor die linke Seite zugewiesen wird, wird die rechte Seite ausgewertet. Und dort verwendest du wieder *zeiger vor zeiger. Das kann so nicht klappen. Und ganz kann ich auch nicht verstehen was du damit bewirken willst. Versuchst du einen Zeiger auf sich selbst zeigen zu lassen? Ganz schlechte Idee, und auch gar nicht hilfreich bei einem Zweifach-Zeiger.

    bis bald
    akari



  • So, hier wie versprochen der Rest:

    freakC++ schrieb:

    arrListe[0]=new CRechteck (4,4);
    
    /*ich weise der ersten Instanz von CRechteck Speicherplatz zu und übergeben zwei Zahlen an den Konstruktor.*/
    

    Richtig. Und dieser zugewiesene Speicherplatz kann über das 1. Element des Array (vom Typ Zeiger auf CRechteck) angesprochen werden.

    Beispiel:

    int FlaecheninhaltB= (*arrListe[0]).Width * arrListe[0]->Height; // beide Zugriffe auf arrListe sind gleichwertig verwendbar
    

    freakC++ schrieb:

    Warum muss ich hier nie vor arrListe ein Sternchen schreiben. Es ist doch eigentlich das gleiche wie mit **zeiger und da musste ich in einem Schritt auch *zeiger schreiben.

    Felder und Zeiger sind miteinander verwandt, das spielt hierbei eine Rolle. Lies dazu bitte den Link unten.

    freakC++ schrieb:

    Vorallem der zweite Quelltext ist mir wichtig, da dieser mir momentan noch Kopfschmerzen bereitet. Warum steht das Sternchen genau vor [zahl].

    Zum 2. Quelltext nochmal (ich glaub du meinst eher den 3. aus deinem vorletzten post): Das Sternchen gehört nicht vor [zahl] sondern hinter CRechteck! CRechteck* ist die Typangabe für das Array, welches also dann vom Typ Zeiger auf CRechteck ist.

    Ich weiß auch nicht wie man es noch einfacher erklären soll. Deklarationen, Definitionen und Initialisierungen sind Grundlagen der Programmierung. Und wenn man mit Zeigern arbeiten möchte, sollte man die Grundlagen dazu zu 90% verinnerlicht haben. Dazu gehören Zeigerdeklaration, Zeigerdefinition und Zeigerdereferenzierung! Ich empfehle nochmal ein einfaches Tutorial zum Thema Zeiger (engl. Pointer) und eins zum Thema Felder (engl. Array)... 😉

    Hier mal was zum Lesen über Zeiger.

    MfG


Anmelden zum Antworten