Verständniss frage zu Zeigern



  • Dem Compiler ist das völlig egal.

    Typ                  *                         pZeiger;
    

    funktioniert auch.

    Lars



  • Interessant wir des dann, wenn du mehrere Zeiger gleichzeitig deklarierst:

    Type *pMyType1, *pMyType2;
    Type* pMyType3, pMyType4;
    

    Was sind das jetzt für Variablen??? Das * ist rechtsassoziativ, das heißt es hängt an dem was rechts davon steht mehr als an dem, was links davon steht (oder war es linksassoziativ???). pMyType4 ist daher kein Pointer, sonder vom Typ 'Type'. Insofern macht es schon Sinn, das * nach C-Style zu schreiben, so vermeidet man Flüchtigkeitsfehler.
    Übrigens könnte man das auch so schreiben:

    Type * pMyType;
    

    PS: Misst, Manni war schneller


  • Administrator

    Heimelchen schrieb:

    Insofern macht es schon Sinn, das * nach C-Style zu schreiben, so vermeidet man Flüchtigkeitsfehler.

    Oder man definiert auf einer Zeile nur eine Variable. In C musste man früher alle Variablen im Kopf der Funktion definieren, daher mag das vielleicht etwas kompakter gewirkt haben, wenn man mehrere Variablen auf einer Zeile definiert hat. In neuerem C und auch in C++ definiert man die Variablen sowieso erst bei der ersten Verwendung, daher sind es meistens sehr wenig auf einmal, und man kann pro Zeile eine Variable hinschreiben, ohne dass man nun 20 Zeilen Variablendefinitionen hat 😉

    Grüssli



  • Hallo,

    zwischen operatoren und operanden dürfen 0 bis n Whitespaces stehen. Das gilt auch für die Deklaration von Zeigern. Es ist also völlig gleichgültig ob Du

    TYPE*zeiger;
    TYPE                         *
    
    zeiger;
    
    TYPE*
    zeiger;
    
    oder
    
    TYPE
    *zeiger;
    

    schreibst.

    Nur: Die Lesbarkeit des Codes für menschliche Leser sollte gewährleistet sein. Auch sollte innerhalb eines Quelltextes die verschiedenen Schreibweisen nicht gemischt werden. Dem Compiler ist das aber wurscht.

    mfg Martin



  • Oh wow danke leute für die Antworten 🙂
    also ist es völlig egal ob ich es links oder rechts schreibe. Ich habe mir es in der kurzen Zeit nämlich so angewohnt es rechts beim Pointer und nicht beim Typ zu schreiben.

    danke euch 🙂



  • Dravere schrieb:

    Oder man definiert auf einer Zeile nur eine Variable. In C musste man früher alle Variablen im Kopf der Funktion definieren, daher mag das vielleicht etwas kompakter gewirkt haben, wenn man mehrere Variablen auf einer Zeile definiert hat. In neuerem C und auch in C++ definiert man die Variablen sowieso erst bei der ersten Verwendung, daher sind es meistens sehr wenig auf einmal, und man kann pro Zeile eine Variable hinschreiben, ohne dass man nun 20 Zeilen Variablendefinitionen hat 😉

    Da kommt noch hinzu, dass lokale Zeiger kaum bis gar nicht vorkommen. In C++ hat man Referenzen, Iteratoren und Smartpointer, rohe Zeiger aber fast nie.
    Lediglich bei Klassen findet man die noch gelegentlich und bei Klassendeklaration ist eine Variable pro Zeile ohnehin allgemein üblich.

    Also kann man den Stern getrost da hinsetzen, wo er hingehört: zum Typen. :p



  • Athar schrieb:

    Da kommt noch hinzu, dass lokale Zeiger kaum bis gar nicht vorkommen. In C++ hat man Referenzen, Iteratoren und Smartpointer, rohe Zeiger aber fast nie.
    Lediglich bei Klassen findet man die noch gelegentlich und bei Klassendeklaration ist eine Variable pro Zeile ohnehin allgemein üblich.

    Also kann man den Stern getrost da hinsetzen, wo er hingehört: zum Typen. :p

    Referenzen benutze ich nur, wenn es unbedingt sein muß oder der Lesbarkeit dient. Normalerweise also gar nicht.

    void func1( TYPE *pointer );
    void func2( TYPE &pointer );
    
    void func3( void )
    {
        TYPE value;
    
        func1( &value );  // hier sehe ich sofort, daß der Parameter by reference übergeben wird
        func2( value );   // hier muß ich mir die Funktionsdeklaration anschauen
    }
    

    Der Stern gehört nicht zum Typen sondern zur Variable, da er sich nur dort auswirkt;

    TYPE *pointer, value;  // Hier wird ein Zeiger und ein Objekt deklariert.
    

    mfg Martin


  • Mod

    @mgaeckler: Da bist du aber ziemlich alleine mit deinem Geschmack. Überhaupt ist auch call-by-(nicht konstanter)-reference eher ungewöhnlich in C++, wenn man es nicht mit dehr großen Objekten zu tun hat.



  • mgaeckler schrieb:

    void func1( TYPE *pointer );
    void func2( TYPE &pointer );
    
    void func3( void )
    {
        TYPE value;
    
        func1( &value );  // hier sehe ich sofort, daß der Parameter by reference übergeben wird
        func2( value );   // hier muß ich mir die Funktionsdeklaration anschauen
    }
    

    Hmm eine frage zu diesem Code. Habe ich das richtig verstanden das beide Funktionen den gleichen Parameter haben ? also ist es egal ob bei der Funktion

    Funktion (TYPE *Pointer)
    

    definiere und dann beim Aufruf

    Funktion( &value )
    

    .

    oder es so mache

    Funktion (TYPE &Pointer)
    

    und beim aufruf dann so

    Funktion( value )
    

    ??

    lg chris



  • mgaeckler schrieb:

    [...]

    func1( &value );  // hier sehe ich sofort, daß der Parameter by reference
    

    [...]

    Und was hilft Dir dieses Wissen? Du weisst immer noch nicht, ob der Wert geändert wird, oder nicht oder ob es ein Zeiger auf const ist, oder nicht. Ergo hasst Du keine Ahnung, was mit dem Wert passiert...



  • Tachyon schrieb:

    mgaeckler schrieb:

    [...]

    func1( &value );  // hier sehe ich sofort, daß der Parameter by reference
    

    [...]

    Und was hilft Dir dieses Wissen? Du weisst immer noch nicht, ob der Wert geändert wird, oder nicht oder ob es ein Zeiger auf const ist, oder nicht. Ergo hasst Du keine Ahnung, was mit dem Wert passiert...

    In C++ hilft es mir tatsächlich wenig, weil es ja eine Referenz sein könnte. In C sehe ich durch die Parameterübergabe by value sofort beim Aufrufer, daß der Wert nicht verändert werden kann. In C++ ist beim Aufruf kein Unterschied zwischen der Parameterübergabe by value und by referenz.

    mfg Martin



  • CodeBase schrieb:

    Hmm eine frage zu diesem Code. Habe ich das richtig verstanden das beide Funktionen den gleichen Parameter haben ? also ist es egal ob bei der Funktion

    Funktion (TYPE *Pointer)
    

    definiere und dann beim Aufruf

    Funktion( &value )
    

    .

    oder es so mache

    Funktion (TYPE &Pointer)
    

    und beim aufruf dann so

    Funktion( value )
    

    ??

    lg chris

    Semantisch ist beides das gleiche. func1 und func2 bekommen beide die Adresse von value.

    mfg Martin



  • mgaeckler schrieb:

    Semantisch ist beides das gleiche. func1 und func2 bekommen beide die Adresse von value.

    mfg Martin

    Das stimmt nicht. Im ersten Fall hat man eine Übergabe per Wert (der Wert des Zeigers).
    Im zweiten Fall hat man eine Übergabe per Referenz, also das Objekt selbst unter dem Namen des formalen Parameters. Hinter der Referenz kann zwar Zeigermechanik am werkeln sein, muss aber nicht.



  • Der Stern gehört logisch zum Typen, da ändert es auch nichts, dass die C-Designer raffiniert sein wollten.
    Warum man diese Eigenheit ignorieren kann, haben Dravere und ich schon erläutert.

    Wenn du eine Funktion aufrufst, wär's übrigens nicht ganz verkehrt, wenn du weißt, was für Parameter sie erwartet und wozu sie verwendet werden. Woraus sich alles weitere ergibt.
    Wenn du gerade fremden Code liest, gibt es notfalls Calltips zur schnellen Aufklärung, wenn etwas mal nicht eindeutig sein sollte.



  • Tachyon schrieb:

    Das stimmt nicht. Im ersten Fall hat man eine Übergabe per Wert (der Wert des Zeigers).
    Im zweiten Fall hat man eine Übergabe per Referenz, also das Objekt selbst unter dem Namen des formalen Parameters. Hinter der Referenz kann zwar Zeigermechanik am werkeln sein, muss aber nicht.

    Das sind Implementierungsdetails, die den Compilerbauer interessieren. Für den C++-Programmierer ist es Jacke wie Hose. Deswegen schrieb ich ja auch "semantisch".

    void func1( TYPE *pointer )
    {
       *pointer = value:
    }
    void main( void )
    {
       TYPE variable;
    
       func1( &variable );
    }
    

    und

    void func1( TYPE &reference )
    {
       reference = value:
    }
    void main( void )
    {
       TYPE variable;
    
       func1( variable );
    }
    

    machen exakt das gleiche.

    mfg Martin



  • Athar schrieb:

    Der Stern gehört logisch zum Typen, da ändert es auch nichts, dass die C-Designer raffiniert sein wollten.
    Warum man diese Eigenheit ignorieren kann, haben Dravere und ich schon erläutert.

    Wer war eher da, Huhn oder Ei?

    Vom Bauchgefühl würd ich dir ja recht geben. Aber mein Kopf stellt sich die Frage, warum der * logisch zum Typen gehört, wenn die Assoziativität ihn an die Variable bindet? Vielleicht hatte the god father of C da eine andere Logik...



  • typedef int * pint;
    pint p;
    

    lese ich als

    int * p;
    

    Damit gehört für mich der * zum Typ.
    Klappt natürlich nur, wenn man für jede Variable eine eigene Zeile opfert, aber das mache ich gerne. Im Weiteren schließe ich mich Dravere an.



  • SeppJ schrieb:

    @mgaeckler: Da bist du aber ziemlich alleine mit deinem Geschmack. Überhaupt ist auch call-by-(nicht konstanter)-reference eher ungewöhnlich in C++, wenn man es nicht mit dehr großen Objekten zu tun hat.

    Das mag sein. Jahrelange Arbeit mit C hat natürlich meinen Stil geprägt. Mag sein, daß er anders wäre, wenn ich gleich mit C++ angefangen hätte. Das gab's damals aber noch nicht.

    Ich habe mir es so angewöhnt:

    Funktionen, die größere Objekte erhalten ohne sie verändern zu wollen, definiere ich mit const referenzen. Funktionen, die die Werte verändern wollen, bekommen einen Zeiger.

    mfg Martin



  • mgaeckler schrieb:

    Ich habe mir es so angewöhnt:
    Funktionen, die größere Objekte erhalten ohne sie verändern zu wollen, definiere ich mit const referenzen. Funktionen, die die Werte verändern wollen, bekommen einen Zeiger.

    So mache ich es auch und es gefällt mir sehr gut.



  • Athar schrieb:

    Der Stern gehört logisch zum Typen, da ändert es auch nichts, dass die C-Designer raffiniert sein wollten.

    Das stimmt, da er sich aber nur auf die nachfolgende Variable, der Typ auf alle Variablen der Deklaration bezieht, ist es trotzdem besser, den * bei der Variable zu schreiben.

    Athar schrieb:

    Wenn du eine Funktion aufrufst, wär's übrigens nicht ganz verkehrt, wenn du weißt, was für Parameter sie erwartet und wozu sie verwendet werden. Woraus sich alles weitere ergibt.

    Korrekt, dem habe ich nichts hinzuzufügen.

    Athar schrieb:

    Wenn du gerade fremden Code liest, gibt es notfalls Calltips zur schnellen Aufklärung, wenn etwas mal nicht eindeutig sein sollte.

    Calltips hat man aber nicht immer zur Verfügung, deshalb habe ich es lieber, wenn ich beim Aufrufer sehe, was Sache ist.

    Ich habe mir das ganze schon vor Jahren angewöhnt und benutze auch heute noch Editoren, die das eben nicht können (vi, Borland C++ um nur zwei Beispiele zu nennen)

    mfg Martin


Anmelden zum Antworten