Adresse eines Zeigers (als Zeiger) dereferenzieren und diesem Zeiger neuen Wert zuweisen



  • Hallo zusammen,

    ich hoffe, die Überschrift sagt schon alles. Nachdem ich lange nichts mehr viel mit Zeigern zu tun hatte, hänge ich nun richtig.

    Zuerst einmal versuche ich mich in c++, aber diese Geschichte ist wohl im c-Forum besser aufgehoben.

    Folgender Code:

    // in .h
    struct s1
    {
    ...
    };
    
    class Test
    {
    ...
    TestMethode(void *Pointer);
    ...
    s1 *Head;
    };
    
    // in .cpp
    TestMethode(void *Pointer)
    {
    s1 *p = (s1*)&Pointer;
    
    p = new s1; // ist natürlich falsch... nur wie mache ich es richtig?
    // ... weitere Zuweisungen in der struct
    }
    
    // Aufgerufen wird die Methode wie folgt:
    TestMethode(&Head);
    

    Und hier hänge ich. Egal was ich versucht habe, ich bekomme die richtige Schreibweise nicht hin. Denn (so ich da richtig denke) ich muß ja die Adresse des Pointers haben, damit ich den Wert ändern kann. Nur wie mache ich das richtig? Das ist keine übliche Pointergeschichte (zumindest für mich). Ich habe mich Stunden damit befasst und bin langsam frustriert. Aber ich brauche die Übergabe via Methode, damit ich auch andere structs so erstellen kann (und nicht nur die in der Klasse.

    Ich hoffe, daß das für viele hier banal ist und ich somit eine Antwort und (noch besser) auch eine Erklärung dazu bekomme :)). Ich stehe hier wie der Ochs vorm Berg.



  • Also nochmal anders gesagt. Head zeigt ja ins Nirvana. Wenn ich Head schon eine struct übergeben habe, dann geht's von da aus problemlos weiter. Aber wenn ich Head in einer Methode erstellen will, dann kann ich nicht einfach Head an Pointer übergeben, da ich ja da nur die Nirvana-Adresse da habe. Also übergebe ich &Head und habe somit die Adresse des Pointers - logisch.
    Eigentlich sollte ja alles klar sein. Ich habe die Adresse eines Pointers *in* einem Pointer gespeichert. Normalerweise sollte ich den Pointer ja einfach benutzen und alles ist gut.
    Nur hier eben nicht - bitte - wie mache ich das richtig und was übersehe ich dabei?

    P.S.: Natürlich sollte ich den Pointer dafür dann auch als void belassen, oder?



  • Hallo, das macht man doch in C++ etwa so:

    class Test { 
    	private:
    		s1* Head; 
    	public:
    		void TestMethode();
    		Test() { 
    			Head = NULL;
    		}
    		~Test() { 
    			delete Head;
    		}
    }; 
    
    void Test::TestMethode() { 
    	if ( Head == NULL ) {
    		Head = new s1;
    	}
    	else {
    		// ...
    	}
    }
    
    int main() {
        Test test;
        test.TestMethode();
    }
    

    Alles andere läuft auf mehr oder weniger komplizierten Murks hinaus:

    class Test { 
    	private:
    		s1* Head; 
    	public:
    		s1** GetPointerAddress() { return &Head; } 
    		Test() {Head = NULL;}
    		~Test() {delete Head;}
    }; 
    
    void testfunc ( void* pv ) {
    // In C++ müssen Zeiger auf void in den entsprechenden Typ gecastet werden.
    	s1** pps1 = (s1**)pv;
    	if ( *pps1 == NULL )
    		*pps1 = new s1;
    }
    
    int main() {
    	Test test;
    	s1** pps1 = test.GetPointerAddress();
    	testfunc ( pps1 );
    }
    

    Gruß,
    B.B.



  • Danke erstmal für die ausführliche Antwort 🙂

    Ich kann das natürlich auch mittels Rückgabewert lösen. Nur wäre eben in meinem Falle die andere Variante schöner. Das Problem ist, daß ich eine recht spezielle Struktur basteln muß. Mit Zeigern auf Zeiger hatte ich das auch schon versucht, nur bleibt das Problem bestehen.

    Normalerweise übergibt man ja einen Pointer, der dann auf die Daten verweist, die man bearbeiten will. Ich muß jedoch einen Pointer übergeben, dem ich dann eine neue Adresse (auf die er zeigen soll) zuweisen soll. Also wie sähe so etwas aus?
    Ich muß den Pointer auch als void übergeben und dann casten, weil ich verschiedene Structs behandeln muß.

    void ChangePointer(void *Pointer, ...)
    {
    MeinTyp *p = new MeinTyp;
    p = new MeinTyp;
    
    // Der Code hier funktioniert natürlich nicht so, wie er soll
    // Er soll nur demonstrieren, was ich erreichen will.
    Pointer = *p; // Dem übergebenen Pointer die neue Adresse zuweisen
    }
    
    // später dann
    ChangePointer(%meinPointer);
    // So. Nun habe ich die Adresse des Pointers an die Methode oben übergeben.
    // Wie weise ich nun diesem Pointer die Adresse der neuen Struct zu?
    

    Es muß dafür doch eine Syntax geben, oder? Und so wäre das eben für mich die einfachere und sichere Variante. Anders herum wäre es kompliziert.



  • Äh ups. Es soll natürlich

    ChangePointer(&Pointer)
    

    und nicht

    ChangePointer(%Pointer)
    

    heißen.



  • Mir würde auch schon die Syntax ohne void Pointer und cast genügen. Also einfach gleich mit meinTyp.



  • Mai schrieb:

    ...Ich muß jedoch einen Pointer übergeben, dem ich dann eine neue Adresse (auf die er zeigen soll) zuweisen soll. Also wie sähe so etwas aus?
    ....

    Genau das passiert in der Funktion testfunc.



  • Big Brother schrieb:

    Genau das passiert in der Funktion testfunc.

    Das stimmt natürlich. Aber auf diese Weise kann ich nicht mit

    *pps1->
    

    weiterarbeiten, da mir der Compiler dann Fehlermeldungen auswirft. Mein erster Gedanke waren ja auch Zeiger auf Zeiger.

    Aber ich hab's nun so gelöst, wie ich es brauche - genau als Deine Antwort kam:

    void ChangePointer(void *Pointer, ...)
    {
    myStruct *p = (myStruct*)Pointer;
    myStruct **ap = (myStruct**)Pointer;
    
    *ap = new TreeNode;
    p = *ap;
    p->member = 0;
    ...
    

    Jetzt funktioniert's auf jeden Fall 🙂 Vielen Dank Dir für Deine Mühe 🙂

    Aber mich würde dennoch noch etwas interessieren:
    Wieso kann ich nicht auf meine Struct-Member mittels *pps1-> zugreifen?
    Die Fehlermeldung ist dann:

    Fehler	1	error C2227: Links von "->member" muss sich ein Zeiger auf Klassen-/Struktur-/Union-/generischen Typ befinden.
    


  • Die Syntax ist: (*pps1)->whatever



  • So wie du vorgehst müsstest du doch für jeden Strukturtypen nen eigenen cast schreiben?
    Kannst du das mit C++ Mitteln nicht lösen? Z.B:

    #include <iostream>
    using namespace std;
    
    struct s 
    { 
    	public:
    	virtual void change_pointer(s* ps) {
    		cout << "s" << endl;
    	}
    }; 
    
    struct s1:public s 
    {
    	virtual void change_pointer(s* ps) {
    		cout << "s1" << endl;
    	}
    };
    
    void change_ptr(s* ps) {
    	ps->change_pointer(ps);
    }
    
    int main() { 
        s s; s1 s1;
    	change_ptr (&s);
    	change_ptr (&s1);
    	return 0;
    }
    


  • Die Syntax ist: (*pps1)->whatever

    Hmm so hatte ich das versucht, aber dafür einen Fehler kassiert. Naja... war wohl gestern einfach zu spät. Mir ist aufgefallen, dass ich den Adressoperator zweimal verwendet hatte (einmal beim Aufruf und einmal beim cast).

    Das mit dem cast stimmt natürlich, aber der Aufwand hält sich in Grenzen da ich nach jedem cast einige Zuweisungen habe. Ich könnte natürlich auch mehrere Methoden definieren, aber das wäre entweder unnötig viel Code oder unnötig viele Aufrufe.

    Und letztendlich ist ein cast sicherlich schneller als eine Virtuelle Methode. Oder vielleicht habe ich einfach zu lange c programmiert 😉

    Ich will diese Methode einfach möglichst schnell (aber gleichzeitig sicher und so flexibel, wie nötig) haben. Keine unnötigen virtual tables, die durchsucht werden müssen, keine unnötigen Methodenaufrufe, etc.


Anmelden zum Antworten