Was ist der unterschie beim zeiger new und &

Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.

  • Hi Leute,
    was ist eigentlich der Unterschied zwischen Zeigern und Referenzen? Wann benutzt man was?



  • Referenzen sind möglichst immer Zeiger vorzuziehen (hope so?!) - es sei denn es geht nicht anders, dies ist in manchen Fällen so:

    - Du die Adresse auch vom Zeiger benötigst [Die Adresse einer Referenz kannst du nicht herausfinden]
    - Du dynamisch Speicher allokierst (new/delete) [Da du einen Zeiger zurückbekommst]
    - Du den Zeiger auch auf 0 setzen willst [Da Referenzen nie 0 sein können]
    - Der Zeiger zu Beginn noch nicht initialisiert werden soll bzw. der Zeiger während seines Lebens verändert werden soll [Da Referenzen immer auf etwas "zeigen" müssen]

    MfG SideWinder





  • Scripta schrieb:

    Hi Leute,
    was ist eigentlich der Unterschied zwischen Zeigern und Referenzen? Wann benutzt man was?

    referenzen sind verkappte zeiger. sie schreiben sich den stern ('*') einfach immer von selber hin, wenn man ne referenz benutzt.
    daher muss auch gefordert werden, daß man sie beim anlegen gleich initialisiert. späteres zuweisen kann ja nicht mehr gehen, weil man imer nur den gereferenzierten verändern würde, der stern ist ja automatisch da.

    naja, eigentlich steht im standard nix davon, daß referenzen zeiger sind. aber nur, um den compilerbauern noch mehr freiheiten zu lassen, zum beispiel gleiche einträge in der symboltabelle statt zeiger oder ähnliches, aber mir scheint, die ganzen details fliegen auch von alleine weg, wenn man sich nen optimierenden compiler vorstellt.

    referenzen können nicht auf 0 zeigen. also

    int i;
    int* pi=&i;
    int& ri=*pi;//ok
    

    und

    int* pi=0;
    int& ri=*pi;//verboten
    

    normale compiler schlücken das zwar, aber verboten isses trotzdem.

    hier greift ein grund für referenzen: der compiler weiß mehr details. daher kann er besser optimieren. ist aber eigentlich um, weil compiler schon recht viel von alleine rausfinden und weil jeder wie er lust hat, __assume__(p!=0) und ähnliches in seinen code einischreiben darf. der grund ist eher irrelevant und mikrooptimierung. bei der gcc kann man afair dem funktionsparameter ne zusatzdeklaration geben, die sagt, daß er ein nicht-null-zeiger ist. betrifft das testen, ob ein nullzugriff passieren wird (der compiler testet eh nur max. einmal pro funktion, beim ersten zugriff, mit zuatz-deklaration halt gar nicht).

    der andere grund ist: refs dürfen nicht auf 0 zeigen, daher verwenden viele deppen sie, um das im prototyp anzugeben. also

    int strlen(char& str);//*str!=0
    

    und

    int strlen(char* str);//str könnte auch 0 sein
    

    nachteile liegen auf der hand:
    - man muß immer überlegen, ob gerade 0 erlaubt ist, oder nicht und daher ref- oder zeiger-version aufrufen. dabei ist der funktion NICHT anzusehen, ob sie 0 erlaubt, weil geneu jene deppen auch dauernd sachen wie

    int strlen(char* str){//str könnte auch 0 sein
       if(str==0) return 0;
       ...
    }
    

    schreiben. also tests ohne jede inhaltliche berechtigung.

    -das debuggen wird um größenordnungen schwieriger. und da mal die zehnfachen kosten im vergleich zum reinen codieren beim debuggen liegen, ist doch das ein wichtiger punkt. stell dir vor, mit dem debugger oder testausgaben fand ich heraus, daß an der markiertren stelle x einen falschen wert hat.

    {
       int x=y;/hier noch guter wert
       f(x);
       cout<<x<<endl;
       x=p;
       g(x);
       p=x;
       h(&x);
    }
    

    und stelle dir weiter vor, du hättest keinen programmierstil.

    {
       int x=y;/hier noch guter wert
       f(x);//kann x verändert haben
       cout<<x<<endl;//kann x verändert haben
       x=p;//kann x verändert haben
       g(x);//kann x verändert haben
       p=x;
       h(&x);//kann x verändert haben
    }
    

    und jetzt mit ein wenig stil. einfach nur: meide refs, außer es sind const refs.

    {
       int x=y;/hier noch guter wert
       f(x);
       cout<<x<<endl;
       x=p;//kann x verändert haben
       g(x);
       p=x;
       h(&x);//kann x verändert haben
    }
    



  • volkard schrieb:

    Scripta schrieb:

    Hi Leute,
    was ist eigentlich der Unterschied zwischen Zeigern und Referenzen? Wann benutzt man was?

    referenzen sind verkappte zeiger.

    Das halte ich für eine falsche Sichtweise. Ich sehe das eher so wie Stephen Dewhurst: References Are Aliases, Not Pointers


  • @Wutz

    Vom Compiler wird nichts als "const behandelt". Was ist ein Programmmodul?

    Schau dir die Exe von meinem Beispiel mit einem Hex-Editor an und du wirst "Hallo Welt" finden.

    Unter einem Programm-Modul verstehe ich eine ausführbare Datei. Diese kann die Dateiendung exe, dll, oder was auch immer haben.

    Und natürlich achte ich auf const correctness. Aber du wirst lachen. Ich kenne sehr viele C Programmierer für denen const ein nutzloses Schlüsselwort ist.

    s1 wird als Zeiger auf char definiert und initialisiert mit der Adresse eines Objektes mit static storage duration, das wiederum vom Compiler definiert wurde mind. groß genug um alle Elemente des Stringliterals inkl. '\0' aufzunehmen, wobei der ändernde Zugriff auf eines dieser Elemente (chars) UB darstellt.

    Verzeih mir bitte dass ich mich mit den Begrifflichkeiten nicht so auskenne. Aber ich behandele Konstanten und String Literale so, als wären sie static const dekaliert worden.

    Und ich glaube ich weis auch was du meinst. Bei einem kleinen Embedded-Prozessor wurden const Variablen im Flash gespeichert und beim Programm-Start ins Ram geladen. Wurden Variablen dagegen als static const deklariert, so wurde der Zugriff direkt auf den Flash Speicher umgebogen. Und der war schreibgeschützt.

    Bei einem anderen Betriebssystem könnte dies anderes implementiert sein.

    s2 ist kein Zeiger auf ein Array.

    Ich habe auch überhaupt nicht s2 gemeint, sondern folgendes:

    #include <stdio.h>
    #include <stdint.h>
    
    int Sum(const int* L, int Size)
    {
      int sum = 0;
    
      for (int i = 0; i < Size; i++)
        sum += L[i];
      return sum;
    }
    
    int main(int argc, char **argv)
    {
        int a[] = {1, 2, 3, 4};
    
        printf("%i", Sum(a, 4));
    	return 0;
    }
    

    L ist ein Zeiger auf ein Array.

    Deswegen sollen C++ler auch string benutzen und nicht irgendwelche Annahmen über C-Strings machen und versuchen, diese nachzubilden.

    Es gibt genau 6 durch den Standard definierte Situationen, in denen ein Arrayname nicht in einen Zeiger zerfällt bzw. immer.
    Wenn du 25 Jahre C programmiert hast, dann wirst du diese kennen.

    Habe ich schon erwähnt dass ich einige C Programmierer kennen, welche nicht const kennen? Ja auch solche welche void CalcSum(void) Programme schreiben?

    Ich will hier auch keinen Flamewar starten, sondern ich stöbere gerade das Buch Effective Modern C++ durch, und da tauchen so viele Detailfragen im Bezug auf Templates Type Deduction auf. Und die eine ist halt der Unterschied zwischen Array und Zeiger.

    s2 wird als Array von char definiert und mit Elementen des Stringliterals initialisiert. Das ist ein wesentlicher Unterschied.
    Arrays kann man kein Stringliteral zuweisen sondern nur damit initialisieren.

    So jetzt bitte nicht ärgern. Hier kommt eine Detailfrage.

    Bedeutet dass das man unter C Variablen mittels = initialisiert?

    Dann dürfte der Code unter C++ nicht funktionen, da ich das Array hier nicht initialisiere, sondern einem String Literal mittels dem = Operator zuweise.

    Was ist der unterschie beim zeiger new und &