Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

TigerClaw25

unregistriert

31

19.07.2017, 12:25

Was ich gerne mal allgemein loswerden möchte: Viele Autoren schreiben bei Zeigern als Funktionsparameter beispielsweise "Zeiger wird übergeben" z.B bei foo(&x);
Dabei wird doch die Adresse an die FUnktion als Parameter übergeben.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

32

19.07.2017, 12:36

Der Zeiger speichert doch die Adresse. Darum ging es doch in den anderen Threads schon die ganze Zeit :D

C-/C++-Quelltext

1
2
int i = 1337; // eine Variable vom Typ int mit dem Wert 1337
int *p = &i; // eine Variable vom Typ Zeiger auf int, mit dem Wert der Adresse der Variable i. Man sagt auch p zeigt auf i.


Übergibst du jetzt p an eine Funktion, so übergibst du die Adresse von i. Übergibst du i an eine Funktion so übergibst du den Wert 1337. Im einen Fall ist der Wert der Variable eben eine Zahl und im anderen Fall ist es eine Adresse einer Integervariable.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

TigerClaw25

unregistriert

33

19.07.2017, 12:47

Das weiß ich. Mir ging es um die Formulierung, nicht um das Verständnis.

Ich habe ein paar Mal in Büchern gelesen, dass mit foo(&wertx); ein Zeiger an die Funktion übergeben wird. Aber diese Beschreibung ist ja falsch, da in dem Fall die Adresse übergeben wird. Manche Bücher verwirren durch ihre Beschreibung.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

34

19.07.2017, 13:03

Ich habe ein paar Mal in Büchern gelesen, dass mit foo(&wertx); ein Zeiger an die Funktion übergeben wird.

Falsch ist das nicht. Die Adresse wird ja eben in einem Zeiger übergeben. Du hast zwar selbst keinen Zeiger angelegt, vorhanden ist der auf dem Stack trotzdem. Das ist an sich aber erst mal nicht so wichtig.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

35

19.07.2017, 13:17

In C++ Speach liefert "&variable" einen rvalue Zeiger. Dass ein Zeiger eine Adresse enthält, ist ein technisches Detail. Rein semantisch ist es ein Zeiger. Punkt.
Den kann man nun per Zuweisung ('=') oder in einen Parameter überführen. Die Aussage bleibt dennoch korrekt, es liefert einen Zeiger und keine Adresse. Eine Adresse hat keinen Datentyp. Ein Zeiger hat einen Datentyp, denn er spezifiziert den Typ, auf den er zeigt. Das ist also ein semantischer Unterschied. Somit ist eher die Aussage "&x liefert die Adresse von x" eigentlich falsch, denn es liefert mehr als nur die Adresse.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

TigerClaw25

unregistriert

36

25.07.2017, 12:11

Ich bin wieder einmal auf etwas verwirrendes gestoßen. Und zwar Zeiger als Member einer Klasse, Klassen und Member beide als Zeiger und Klassen als Zeiger und Member nicht.

Beispiel:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class CSpieler 
{
    public:
    int ptr;

};

int main ()
{
    CSpieler *Spieler1 = new CSpieler;
    (*Spieler1).ptr = 50;
    
    cout << "Wert " << Spieler1->ptr << endl;
    cout << "Adresse " << &Spieler1->ptr << endl;

    system ("Pause");
    return 0;
}


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class CSpieler 
{
    public:
    int *ptr;

};

int main ()
{
    CSpieler *Spieler1 = new CSpieler;
    (*Spieler1).ptr = new int;          // new liefert Adresse auf Integer
    *(*Spieler1).ptr = 50;
    
    cout << "Wert " << *Spieler1->ptr << endl;
    cout << "Adresse " << Spieler1->ptr << endl;

    system ("Pause");
    return 0;
}


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class CSpieler 
{
    public:
    int *ptr;

};

int main ()
{
    CSpieler Spieler1;
    Spieler1.ptr = new int;         // new liefert Adresse auf Integer
    *(Spieler1.ptr) = 50;
    
    cout << "Wert " << *Spieler1.ptr << endl;
    cout << "Adresse " << Spieler1.ptr << endl;

    system ("Pause");
    return 0;
}


Ich hoffe alle drei Beispiele richtig gemacht zu haben, da eigentlich an genau solchen Beispielen eben die Fehler entstehen. Ich nahm an die Schreibweise für das dritte Beispiel wäre z.B. "Spieler1.*ptr". Dass das Sternchen beispielsweise im dritten Beispiel "*Spieler1.ptr" steht, deutet für mich als unerfahrenen Anfänger auf eine Klasseninstanz auf dem Heap.

Wenn ich mich jetzt an das gelesene erinnere, bedeutet der Punktoperator, dass man eben auf ein Memberelement zugreift. Daher sehe ich für mich in Spieler1.ptr ersteinmal nur den Memberzeiger "ptr". Dennoch würde es mich interessieren, welche Methoden ihr dafür verwendet, nicht durcheinander zu kommen.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

37

25.07.2017, 12:33

deutet für mich als unerfahrenen Anfänger auf eine Klasseninstanz auf dem Heap.
Nein. Spieler1 ist eine Instanz auf dem Stack. Deswegen greifst du per "." auf seine Eigenschaft "ptr" zu. Der "ptr" ist aber ein Pointer und somit der Gesamtausdruck "Spieler1.ptr" ebenfalls, denn das ist ja quasi nur der "lange Pfad", unter dem du auf "ptr" zugreifst. Und diesen Pointer musst du dereferenzieren, wenn du was reinschreiben willst in den int, auf den er zeigt. Also: *(Spieler1.ptr).
Wäre Spieler1 eine Instanz auf dem Heap, müsstest du entweder (*Spieler1).ptr nutzen oder Spieler1->ptr.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

TigerClaw25

unregistriert

38

25.07.2017, 13:29

Letzteres hat jedoch den Nachteil, dass für die Adresse Dereferenziert und dann wieder referenziert werden muss:

&(*Spieler1).ptr für die Adresse
&Spieler1->ptr

Das hier geht leider nicht: Spieler1.ptr , obwohl es auf den ersten Blick den Anschein macht.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

39

25.07.2017, 13:52

Letzteres hat jedoch den Nachteil, dass für die Adresse Dereferenziert und dann wieder referenziert werden muss:

&(*Spieler1).ptr für die Adresse
&Spieler1->ptr

Das hier geht leider nicht: Spieler1.ptr , obwohl es auf den ersten Blick den Anschein macht.

Wenn Spieler1 ein Zeiger ist geht Spieler1.ptr natürlich nicht. Dein Code oben ist also korrekt falls Spieler1 ein Zeiger und ptr eben keiner ist. Warum sollte es den Anschein machen dass du in diesem Fall mit Spieler1.ptr zum Ziel kommst?
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

TigerClaw25

unregistriert

40

25.07.2017, 14:11

Weil das Weglassen von "*" die Adresse liefert. Da kommt man leicht durcheinander. Ich habe mir dazu einfach folgendes gemerkt:
Mit "->" oder "(* xyz)." erlange ich Zugriff auf die Klassenmethoden- und membervariablen. nach dem Operator gebe ich an, auf welches Element ich Zugriff erlangen möchte wie "Spieler1->ptr". Möchte ich die Adresse des Gesamtausdrucks/elements, setze ich "&" davor, also "&Spieler1->ptr". So versuche ich es mir zu merken.

Was ich im Buch persönlich sehr schade als kleine Überprüfung finde, ist eine Art Kontrolle wie z.B. bei folgendem Code:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
CSprite::CSprite()
{
    //Zeiger auf Renderer holen, damit framework nicht ständig aufgerufen wird
    m_pRenderer = g_pFramework->GetRenderer();
}
// Nicht-animiertes Bild laden

void CSprite::Load(const string sFilename)
{
    // Bitmap temorär in einer Surface laden
    SDL_Surface *pTemp = SDL_LoadBMP(sFilename.c_str());

    // prüfe, ob alles glatt ging
    if (m_pImage == NULL)
    {
        cout << "Fehler beim Laden von " << sFilename.c_str();
        cout << endl;
        cout << "Fehlermeldung: " << SDL_GetError() << endl;

        // Framework dann herunterfahren
        g_pFramework->Quit();

        exit(1);
    }


Im Buch steht, dass "pRenderer" nicht in CSprite freigegeben werden darf. Wenn ich bisher alles richtig verstanden habe, ist der Grund der, dass "g_pFramework->GetRenderer()" im Prinzip einen Zeiger auf das erzeugte Objekt zurückgibt. "m_pRenderer" bekommt also einfach eine Adresse eines anderen Zeigers von Framework, der auf die Speicheradresse des Objekts zeigt. Das heißt, wenn man "m_pRenderer" im Destruktor von CSprite freigibt, den zurückgegebenen Zeiger von "g_pFramework->GetRenderer()" aber woanders weiter verwendet, ist dieser undefiniert. VErstehe ich das richtig?

"if (m_pImage == NULL)" ist auch etwas unsauber. Wenn ich das richtig verstehe, zeigt der Zeiger "m_pImage", der in der Klasse deklariert wurde, auf irgend eine Adresse, nur nicht auf NULL; da nicht mit NULL initialisiert. Daher funktioniert das. Wenn ich dem Zeiger aber aus versehen im Konstruktor NULL zuweise, komme ich garnicht dazu mein Bild zu laden, weil die Bedingung immer zutrifft.

Werbeanzeige