Verständniss frage zu Zeigern


  • 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



  • volkard schrieb:

    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.

    Wobei das wiederum eher die typedef-Syntax betrifft als die "Logik" des *.

    Wie gesagt, vom Bauch her teile ich die Logik, dass der Pointer ein Typ ist und seine "Bezeichnung" zur Typbezeichnung gehört. Aber die Syntax sagt nunmal was anderes...

    Wobei ich solche Diskussionen immer spannend finde. Bei Text- oder Bildinterpretationen, wie man sie in der Schule macht, diskutieren Leute ewig darüber, was der der Schöpfer mit der Aliteration oder Farbmischung ausdrückung möchte. Vielleicht ist dem Autor kein Wort mit einem anderen Buchstaben eingefallen und begeisternde Farbvariationen haben ja bekanntlich auch "künstlerisch hochbegabte" Affen geschafft.
    Sich darüber zu streiten, was "üblich" ist, was "guter Stil" ist, was "logisch" ist oder auch "dumm", wären alle einer Meinung, gäbe es keinen Fortschritt mehr.

    Um zum Thema zurückzukommen: vielleicht ändert jemand die Syntax so, dass

    type* pMyVar1, pMyVr2;
    

    zwei Pointer deklariert. Solange das nicht so ist, gehört der Stern logisch "nach rechts". Wo man ihn hinschreibt, bleibt nach wie vor scheiß egal.



  • mgaeckler schrieb:

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

    Eben nicht. Übergabe per Wert bzw. als Referenz interessiert mich als Entwickler, weil es einige große Unterschiede gibt.
    Referenzen kann man z.B. nicht auf Referenzen zeigen lassen. Auf Zeiger hingegen schon. Zeiger dürfen auf NULL bzw. auf ungültige Werte Zeigen. Referenzen hingegen nicht. Einen Zeiger kann ich beliebig auf irgendetwas zeigen lassen, weil es eine normale Variable eines Zeigertyps ist. Auf Referenzen trifft das nicht zu.
    Deine Aussage

    mgaeckler schrieb:

    func1 und func2 bekommen beide die Adresse von value.

    ist falsch.



  • Natürlich gehört der * zum Typ. Aber [] bei Arrays gehört auch zum Typ. Überhaupt gehört in einer Deklaration alles außer dem deklarierten Namen zum Typ:

    void (*f)(int(&)[10]);
    //<-----> <----------->
    //  Typ  ^  auch Typ
    //       |
    //   Bezeichner
    


  • Tachyon schrieb:

    Eben nicht. Übergabe per Wert bzw. als Referenz interessiert mich als Entwickler, weil es einige große Unterschiede gibt.
    Referenzen kann man z.B. nicht auf Referenzen zeigen lassen. Auf Zeiger hingegen schon. Zeiger dürfen auf NULL bzw. auf ungültige Werte Zeigen. Referenzen hingegen nicht. Einen Zeiger kann ich beliebig auf irgendetwas zeigen lassen, weil es eine normale Variable eines Zeigertyps ist. Auf Referenzen trifft das nicht zu.

    Natürlich gibt es auch Unterschiede zwischen Referenzen und Zeigern. Referenzen wurden schließlich nicht nur aus Spass erfunden. Das kommt aber daher, weil Zeiger syntaktisch anders verwendet werden und man/frau mit Zeigern mehr Unfug treiben kann.

    Man kann aber auch mit Referenzen Unfug treiben:

    #include <string.h>
    
    static void destroyer( void )
    {
    	int array[255];
    
    	memset( array, 0, sizeof( int ) * 255 );
    
    	printf( "", array );
    }
    
    static int &func( void )
    {
    	int var = 5;
    	int &ref = var;
    	ref = 6;
    
    	return ref;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int &var = func();
    	destroyer();
    
    	printf( "%d", var );
    	return 0;
    }
    

    Tachyon schrieb:

    Deine Aussage

    mgaeckler schrieb:

    func1 und func2 bekommen beide die Adresse von value.

    ist falsch.

    Eine Referenz ist letztendlich nichts anders als eine Adresse wie auch immer der Compilerbauer das realisiert hat.

    mfg Martin



  • mgaeckler schrieb:

    [...]
    Eine Referenz ist letztendlich nichts anders als eine Adresse wie auch immer der Compilerbauer das realisiert hat.

    mfg Martin

    Wie kommst Du nur auf so was?



  • mgaeckler schrieb:

    Man kann aber auch mit Referenzen Unfug treiben:

    Man kann mit mit so ziemlich allem undefiniertes Verhalten hervorrufen, so wie du es hier zeigst.



  • Tachyon schrieb:

    mgaeckler schrieb:

    [...]
    Eine Referenz ist letztendlich nichts anders als eine Adresse wie auch immer der Compilerbauer das realisiert hat.

    mfg Martin

    Wie kommst Du nur auf so was?

    Mehr als 30 Jahre Erfahrung. Selber schon bei einem Compilerbauer gearbeitet.


Anmelden zum Antworten