(Zeiger auf Zeiger) Verständnissproblem



  • Ja, eigentlich müsstest du es machen, aber ein void* kann auf beliebige Daten verweisen, also ohne Probleme auch auf einen anderen void* (oder sogar auf sich selber).



  • Hallo,

    ok ich glaube mein Problem an sich ist dann eher die Schnittstelle zur Funktion zu verstehen:

    Wenn ich weiß das es Zeiger gibt und Variablen (integer, long, char, ...) aud die ich dann zeigen kann, also die Variable besitzt einen Wert (

    int x=2;
    

    ) dann wird der Wert ja irgendwo im Speicher gehalten. Setze ich einen Zeiger drauf

    int *intPTR; und intPTR=&x;
    

    kann ich jetzt Werte nach x schreiben ohne x zu kennen (könnte auch y) heißen.( Praktische Beispiel ist die Swap Funktion , die Werte austauscht und ich Zeiger übergebe, weil ich sonst Schwierigkeiten bekomme die Werte zu tauschen.)

    "int** ppi = π"
    

    habe ich dann eben nur einen Zeiger nämlich (pi)
    Wenn ich aber eine Funktion schreibe oder Aufrufe ist dann (...aber nicht hauen...)

    ...,(int** ppi) &pi,...
    

    dann vom Prinzip das gleiche wie eben sie Initializierung mit int** ppi=.... Weil eben das Konstrukt (void**) &myStruct auch einer Funktion im Paramterbereich übergeben wird und ich nicht auf die Reihe kriege was dort eigentlich genau passiert. Ich kann eine Variable deklarieren und einen Zeiger draufsetzen, aber wenn ich mir Funktionsschnittstellen ansehen, dann klemmt's.

    Gruß
    Franky



  • Einen Zeiger hast du übrigens auch bei Arrays. Dort zeigt der Zeiger auf das erste Element.
    Einen Zeiger auf einen Zeiger kann man so für mehrdimensionale Arrays nutzen, wie viele Grafikbibliotheken es zB benötigen (wenn auch manchmal nur intern oder was auch immer).

    Das hast du zB bei char* meinArray[4]; meinArray ist dann vom Typ char** und verweist auf den Punkt im Speicher in dem die vier Adressen hintereinander stehen, die auf weitere Speicherbereiche verweisen, an denen dann Zeichenketten stehen (wenn man denn was initialisiert) können.



  • void mySwap(int *a, int *b){ int i; i=*a; ...}
    

    wenn dann mySwap aufgerufen wird dann so:

    mySwap(&x, &y)
    

    Ist das also das gleiche wie

    int* a; int i; a=&x; i=*a;
    

    weil dann müßte ja (Aufruf)

    ...myFunc(..., (void**) &myStruct,...)
    

    (wobei das ja nicht weiß, eben nur als Beispiel, zum Verständniss was ich da mache) (mögliche Deklaration)

    ...myFunc(..., void* paramStruct,...)
    

    oder so?

    Gruß
    Franky



  • Es kommt drauf an was das für eine Funktion ist. Willst du selber eine erstellen?

    Wenn du nur den Pointer auf ein Objekt brauchst, dann:
    void myFunc(myStruct *s);

    und Aufruf mit myFunc(&meinStruktOderObjekt);

    Void-Pointer braucht man wirklich nur in seltenen Fällen.



  • int i=23123;
        int *p1=&i;
        int *p2;
        p2=p1;
    
    	cout << *p2 << " " << *p1 << endl;
    // ausgabe: 23123 23123
    

    das hier scheint mit:

    int i=23123;
        int *p1=&i;
        int **p2;
        p2=&p1;
    
    	cout << **p2 << " " << *p1 << endl;
    // ausgabe: 23123 23123
    

    äquivalenz zu sein.

    da wird man wohl nicht erkennen können, wofür ** gut sind?



  • Du kannst ja soviele Pointer auf Pointer auf Pointer etc erstellen wie du willst, solange du die immer wieder alle dereferenzierst, macht das keinen Unterschied (Speicherverbrauch für die einzelnen Pointer mal ignoriert).

    Im Grunde erstellst du jedesmal ein Inhaltsverzeichnis für ein Inhaltsverzeichnis in einem Buch. So als Metapher mal gedacht. Da kannst du fünfhundert verschachtelte Inhaltsverzeichnisse haben, solange du denen immer brav bis zum eigentlichen Text folgst, nehmen die nur Platz weg. 😉



  • Hallo,

    ...sondern nur die Parameterübergabe der Art

    ..., (void**) &myVariable,...
    

    verstehen.
    Bislang dachte ich immer Zeiger verstanden zu haben, aber dann habe ich den oben angegebenen Code gesehen und war verblüfft. Weil eine Addresse übergeben wird und diese konvertiert in einen void Zeiger auf void Zeiger. Also habe ich mich gefragt, was das soll. Weil ich das noch nie gesehen habe und meine Bemühungen zu verstehen was da abläuft ins Leere gelaufen sind.

    Gruß
    Franky



  • Zeig doch mal die ganze Funktionssignatur.

    Also wenn eine Funktion einen Pointer auf einen void* haben will, musst du ihr natürlich auch einen geben. Daher das casten zu void**. Und myVariable ist vermutlich ein typedef, irgend ein Pointer.



  • ..ist aus dem Buch von David Kruglinski, George Sheperd, Scot Wingo
    "Inside Visual C++ 6.0; Kapitel 24, Seite 533 ff."

    Dort wird a)

    eine Struktur definiert

    struct IMotion
    {
      virtual Fly()=0;
      virtual GetPosition()=0;
    };
    

    b) eine Klasse Spaceship

    class Spaceship: public IMotion
    {
      protected:
        m_nPosition;
      public:
        CSpacehip() {m_nPosition=0;}
        void Fly();
        int& GetPosition() {return m_nPosition}
    };
    

    c) eine Schnittstelle

    IMotion *pMot;
    GetClassObject (CLSID_CSpaceship, IID_IMotion, (void**) & pMot);
    

    Das ganze um Konstrukte wie eben...

    STDAPI OleCreatePictureIndirect( 
      PICTDESC* pPictDesc,
                     //Pointer to the structure of parameters for picture
      REFIID  riid,  //Reference to the identifier of the interface
      BOOL fOwn,     //Whether the picture is to be destroyed
      VOID** ppvObj  //Address of output variable that receives the 
                     // interface pointer requested in riid
    );
    

    ...zu verstehen, weil für mich das ganze irgendwie ähnlich aussieht, aber ich mit (void) &...** irgendwie nicht klarkomme. Wei lich nicht wirklich weiß was das dort macht!

    Gruß
    Franky



  • Ich seh das so:

    '*' bedeutet: Pointer (völlig unabhängig von dem Typ auf was der Pointer Zeigt). Es ist ja nur eine Adresse im Speicher - d.h. ein Pointer selbst sieht immer gleich aus (Adresse eben) - egal auf was für einen Typ er zeigt.

    Insofern ist void* ein Pointer auf etwas vom Typ void (also etwas unbekanntes das man halt dann wahrscheinlich noch casten muss um damit weiterzuarbeiten)

    void** ist einfach ein Pointer auf einen Pointer der auf etwas vom Typ void zeigt.

    Könnte z.B. von Nutzen sein wenn man einen ganze Liste von Pointern auf Ergebnisse unterschiedlichen Typs hat und über eine andere Funktion einen Pointer auf eine Stelle in dieser Liste zurückgibt.

    Oder seh ich das jetzt falsch?



  • FrankTheFox schrieb:

    ..ist aus dem Buch von David Kruglinski, George Sheperd, Scot Wingo
    "Inside Visual C++ 6.0; Kapitel 24, Seite 533 ff."

    Dort wird a)

    eine Struktur definiert

    struct IMotion
    {
      virtual Fly()=0;
      virtual GetPosition()=0;
    };
    

    Stehn die Methoden da wirklich so ohne Rueckgabetypen? Ich glaube nicht. Falls doch, dann suche einen Altpapiercontainer in deiner Naehe auf, der das Buch liebevoll aufnehmen wird.

    IMotion *pMot;
    GetClassObject (CLSID_CSpaceship, IID_IMotion, (void**) & pMot);
    

    Die Funktion GetClassObject erwartet als dritten Parameter offenbar einen Zeiger auf einen void-Zeiger (vermutlich um dort eine Adresse zu hinterlassen, man koennte stattdessen auch eine Referenz auf einen Zeiger verwenden). Dein pMot ist aber ein Zeiger auf ein IMotion, damit ist &pMot ein Zeiger auf einen IMotion-Zeiger (IMotion**). Deshalb steht dort das (void**), um den Zeiger-auf-Imotion-Zeiger in einen Zeiger-auf-void-Zeiger zu veraendern.

    Das ganze um Konstrukte wie eben...

    STDAPI OleCreatePictureIndirect( 
      PICTDESC* pPictDesc,
                     //Pointer to the structure of parameters for picture
      REFIID  riid,  //Reference to the identifier of the interface
      BOOL fOwn,     //Whether the picture is to be destroyed
      VOID** ppvObj  //Address of output variable that receives the 
                     // interface pointer requested in riid
    );
    

    ...zu verstehen, weil für mich das ganze irgendwie ähnlich aussieht

    hier ist OleCreatePictureIndirect eine Funktion, die utner anderem einen VOID** erwartet - vom Namen her vermutlich mehr oder weniger das gleiche wie ein void**

    Der Unterschied: bei GetClassObject handelt es sich um einen Funktionsaufruf mit einem cast nach void**. Bei OleOleLangerName um eine Funktionsdeklaration, die dem Anwender sagt dass das letzte Argument ein VOID** zu sein hat.
    Beides (vor allem das letzte) sieht mir etwas arg C-Style aus, vermutlich kann man das auch schicker loesen.



  • ich glaub' ich hab's!!!! Wenn ich falsch liege, dann sagt's mir:

    Also meine Lösung:

    void function mySwap(int *a, int *b)
      {
       .......
      }
    

    wird so aufgerufen...

    mySwap( &a, &b);
    

    die Deklaration von GetClassObject setzt aber

    ..., void** ppvObj,...
    

    voraus. Also einen Zeiger auf einen Zeiger! Ich muß dann nicht nur &...
    schreiben, sondern muß das zu einem Zeiger auf einen Zeiger machen, also dann ein (void)** vor die Addresse, also das &! Also nur ein cast! Ich dachte weil ich das klammere und vor das Addressop setzte, hätte das andere Bedeutung.



  • Ja, da stehen Rückgabewerte.



  • Das casten zu void** ist natürlich nur nötig, wenn die Funktion das auch haben will. Genauso gibt es int**. Der Sinn der Funktion ist es dann, den Pointer pMot zu verändern. Würde nur pMot und nicht dessen Adresse übergeben werden, hätte die Funktion nur eine Kopie des Pointers und es würde nichts bringen diese zu verändern.


Anmelden zum Antworten