Endlich Zeiger (Pointer verstanden... oder doch nicht?

  • Hi zusammen.


    Wie ja schon anderweitig erwähnt bin ich nun endlich dabei mein Wissen, so gut es mir möglich ist, um C++ zu erweitern.


    Allerdings scheine ich dann doch hin und wieder mal zu stocken. In diesem Fall bei den Pointern.


    Um mal auszuprobieren, was für ein Geschwindigkeitsvorteil sich aus der Benutzung von Pointern ergibt habe ich mir mal ein ganz simples Programm mit ein paar For-Schleifen geschrieben, in denen ein Zähler hochgezählt wird.


    Die erste Grundlage des Programms sind drei normale Schleifen.


    Die erste Schleife ist ja klar. Ganz normale Schleife, Zugriff normal über die Integervariable.

    Die zweite Schleife benutzt halt den Pointer auf die Integervariable. Funktioniert ebenfalls.

    In der dritten Schleife wollte ich es einfach mal etwas übertreiben und habe sowohl den Schleifenzähler als auch die Integervariable als Pointer in gebrauch. Dies funktioniert nicht.


    Es ergeben sich zwei merkwürdige Phänomene.

    Das erste ist, wenn ich das Programm öfter starte kommt es oft auch vor, dass Schleife zwei langsamer ist als Schleife 1. Ich kann darin kein Muster oder so erkennen, es scheint eher zufällig zu sein.

    Das Zweite ist halt, offensichtlich kann man den Schleifenzähler nicht über den Pointer benutzen. Er durchläuft die Schleife gar nicht, 0 Sekunden, Wert von myInteger = 0.


    Ich dachte ja ich hätte es mit den Pointern verstanden, offensichtlich mache ich aber dennoch einen Denkfehler. Kann mir einer sagen welcher das ist?

  • Also zu 3)

    Ich hab es nur mal theoretisch betrachtet, um es zu bestätigen müsste man mit nem Debugger rein.


    Zuerst einmal müsstest du dich über die Operator Precedence in C++ bewusst machen:

    https://en.cppreference.com/w/…guage/operator_precedence


    Du siehst hier, dass der Increment eine höhere Precendence hat. Somit wird zuerst der Pointer inkrementiert (also die Adresse wird inkrementiert) und danach dereferenziert (was irgendetwas sein kann, was zufällt dort steht.)


    Was klappen könnte wäre (*ptrY)++


    Edit: Vielleicht noch praktisch zu wissen. Ein Increment eines pointiert ist nicht ein Increment der Adresse um 1 Bit, sondern ein Increment um die Größe des Inhalts des Pointers.

    Ein Pointer der auf ein 16 Bit integer zeigt, würde also um 16 Bit inkrementiert werden. Falls dein Pointer auf ein Element eines Arrays zeigt, sorgt das also dafür, dass der resultierende Pointer auf das nächste Element zeigt.


    Edit2: Habe mal etwas rechtschreibung, verbessert.

    Also im Grunde sieht es so aus als hättest du Grundlegend Pointer verstanden, nur wusstest du nicht, dass *ptrY++ anders interpretiert wird, als du es dir gedacht hast.

  • Ah cool. Habs gerade ausprobiert und es funktioniert jetzt. Auch wenn es mich wundert, dass die auf die Spitze getriebene Version, also Version 3, länger dauert als Version 2.


    Also kann man in C++ ganz lässig auch Dinge übertreiben und muss dann wohl auch damit rechnen, das unvorhergesehene Dinge passieren. Weil das, was du beschrieben hast, steht nun nicht gerade im Dummy-Buch. Oder ich habe den Teil noch nicht erreicht, kann auch sein. Schließlich kann man ja nicht nur lesen, sondern man muss mit dem gelesenen auch mal etwas spielen. :P


    Ja, C++ scheint richtig gut mächtig zu sein. Bin ich von C# usw. natürlich nicht gewohnt. Hoffentlich sprenge ich meinen Rechner nicht in die Luft bevor ich hier passenderweise noch mal fragen kann ob das so gehört. :D

  • Ah cool. Habs gerade ausprobiert und es funktioniert jetzt. Auch wenn es mich wundert, dass die auf die Spitze getriebene Version, also Version 3, länger dauert als Version 2.

    Falls der Compiler hier nichts optimiert werden bei 3 auch mehr Dinge getan.

    Zuerst einmal muss ja auf den Speicher zugegriffen werden auf den der Pointer liegt, dann muss der Inhalt ausgelesen werden, dies ergibt dann die Adresse der eigentlichen Variable die du verändern willst und diese wird dann verändert.

    Am Ende macht der Code das was zu schreibst, wenn du also mehr Befehle in den Code packst, dann muss auch mehr getan werden. Der Vorteil von Pointern kommt bei Objekten, hier willst du ja oft nicht das ganze Objekt temporär Kopieren, da ein Objekt oft viel mehr Speicher benötigt. Da kann es oft Sinn machen nur den Zeiger zu übergeben. In Spielen will man ja auch z.B. über Funktionen ein bestimmtes Objekt auf der Welt manipulieren, auch hier benötigt man Zeiger.

    C#, Java, etc. arbeiten mit der Annahme dass alle deine Objekt variablen eigentlich nur Zeiger sind.

    Wenn du in UE4 mit C++ arbeitest wirst du merken, dass du gar nicht mal so anders denken musst als in C#, weil die Grundlegenden Klassen der Engine schon das ganze Low Level zeug übernehmen und du nur noch High Level Code schreibst, der sich nicht so viel um Memory Management kümmern muss.


    Am Ende sollte es auch in C++ für dich eher die Regel sein, so zu programmieren, dass es verständlich ist. Gute Wartbarkeit deines Codes ist wichtiger, als dass du optimierst ohne Ende, dann aber deinen Code nicht mehr pflegen oder fixen kannst, weil du nicht mehr durchsteigst.


    Ja, C++ scheint richtig gut mächtig zu sein. Bin ich von C# usw. natürlich nicht gewohnt. Hoffentlich sprenge ich meinen Rechner nicht in die Luft bevor ich hier passenderweise noch mal fragen kann ob das so gehört.

    Ja C++ ist ziemlich mächtig. Im Grunde überlässt C++ dir sehr wie Kontrolle darüber was wie in den Speicher kommt oder was man wie wieder ausließt. Von daher ist das natürlich auch eine Sprache mit der Betriebsysteme geschrieben werden. Man kann auch über Pointer und Casting recht interessante Dinge tun, wie aber heutzutage wohl eher nicht mehr praktisch sind.

    Was mir immer gerne gefällt ist die Carmack Wurzel (Fast Inverse Square Root, ist aber nicht von John Carmack erfunden.)

    Da wird z.B. über die Art wie ein Float im Speicher abgelegt ist und type casting des Pointers + einer magic number die inverse Quadratwurzel einer Zahl approximiert.

  • Na ich glaube das mit Unreal wird wohl noch dauern. Üben tue ich momentan mit Code:Blocks und GCC. Unreal liebt ja eher Visual Studio. Und was es, zumindest für mich, etwas schwierig macht, bzw. auch Projekte in Visual Studio allgemein, Visual Studio und Unreal geben jede menge automatisch generierten Code vor. Ich muss mich also viel in Code einlesen, oder ihn einfach ignorieren, der nicht unbedingt meinem Programmierstil entspricht, oder wo ich vielleicht schon etwas im Code habe, von dem ich gar nicht weiß, dass es schon vorhanden ist, weil ich nicht unbedingt alle Dateien durchsuche. Klingt vielleicht komisch, aber ich denke du weißt, was ich meine.


    Ich persönlich ziehe es eigentlich vor Projekte wirklich bei Null zu starten, auch wenn es viel Schreibarbeit ist, dafür ist es dann aber da zu finden wo ich es vermute und wie ich es vermute.