Problem mit Pointer



  • Moin,
    hab hier ein Problem mit nem Quellcode...

    Also hier erstmal der Code:

    #include <iostream>
    
    using namespace std;
    
    // Prototypen
    
    void BerechnePunkte (int *pPunkte, int Bonus);
    
    int main()
    {
    	int iPunkte = 500;
    	int iBonus = 150;
    
    	// Punkte vor dem Funktionsaufruf anzeigen
    	cout << "Punkte vor dem Funktionsaufruf: ";
    	cout << iPunkte << endl;
    
    	// Es wird die Funktion "BerechnePunkte" aufgerufen,
    	// der als Parameter die ADRESSE der Variablen
    	// "Punkte" übergeben wird sowie der Wert der Variablen
    	// "Bonus"
    
    	BerechnePunkte (&iPunkte, iBonus);
    
    	// Punkte nach dem Funktionsaufruf
    	cout << "Punkte nach dem Funktionsaufruf: ";
    	cout << iPunkte << endl;
    
    	return 0;
    
    }
    
    void BerechnePunkte (int *pPunkte, int iBonus)
    {
    	*pPunkte += iBonus;
    }
    

    So jetzt hab ich da ein Prob. In der Funktion "BerechnePunkte" wird ja *pPunkte benutzt um den Wert zu ändern bzw. wirdd so iBonus hinzuaddiert! Das is ja auch normal so weil ohne des Sternchen würd man ja nur auf die Adresse zugreifen und nicht auf den Wert, der an dieser stell gespeichert ist! Aber woher kennt die Funktion "BerechnePunkte" überhaupt *pPunkte?

    *pPunkte wurde ja nirgends erstellt...!? Normalerweise macht man doch vorher immer noch eine Zuweisung:

    int iPunkte = 1000;
    int *pPunkte = NULL;
    
    pPunkte = &iPunkte;
    

    Oder hab ich da irgendwas nicht richtig verstanden....



  • Hi!

    int *pPunkte
    

    Is doch ein Parameter der Methode...
    grüße



  • Die adresse kennt deine Funktion, weil du sie im Hauptprogramm berechnet hast (durch die Übergabe von **&**iPunkte an deine Funktion).

    (btw, in C++ nimmt man für solche Konstruktionen lieber Referenzparameter)



  • int *pPunkte
    

    Is doch ein Parameter der Methode...

    Ahso... Also ist das praktisch, wie wenn man in einer for-schleife das erste mal int i hat z.B. ... Die Variable i hat man vorher ja auch nicht deklariert.

    @CStoll

    Ja mit Referenzen hab ich mich noch nie beschäftigt. Das schau ich mir jetzt erst an, da ich auch nochmal mit Pointer alles wiederholten wollte, da es ja doch ein recht kompliziertes Thema ist (Wie ich finde).



  • Hi!

    Nein, so ist das nicht. Du übergibst ja die Adresse deiner Variable an die Methode, also an den Zeiger.
    Daher kannst du innerhalb der Methode auf den Speicherbereich der Variable zugreifen.

    grüße



  • Hi.

    Ja das is mir klar soweit. Also das ich die Variable nicht in der funktion (Methode?)neu deklarieren muss und so. Aber ich benutze ja nicht iPunkte sondern *pPunkte.

    Daher war meine Frage warum das geht. Weil wenn ich z.B. anstatt *pPunkte inder Methode *pIrgendEinName benutze, meckert der Compiler rumm wegen dem nicht deklarierten Zeiger...
    Also findet die Deklaration von *pPunkte in dem Funktionskopf statt...
    Bzw. in der Parameterliste....Weil woaners kommt ja *pPunkte nicht vor.

    Da hatts mich halt nur gewundert das der Compiler das so auch annimmt.

    EDIT: Ich mein das übrigens gennerell , also auch in der Main Funktion.
    Weil da könnt ich ja *pPunkte auch benutzen... Ohne den vorher deklariert zu haben (Es sei denn oberes trifft zu...also das mit den Parametern)



  • Ich denke das Verständnisproblem liegt darin dass der * zwei verschiedene Bedeutungen hat:

    int* pPunkte;
    

    Der Stern bezieht sich auf den Typ. pPunkte ist der Name der Variable, die eine Adresse-von-int enthält.

    printf("%d\n", *pPunkte);
    

    Der Stern bezieht sich auf die Variable. *pPunkte ist der Integer, der an der Adresse gespeichert ist, die in der Zeigervariable pPunkte abgelegt ist.

    BerechnePunkte (&iPunkte, iBonus);
    
    void BerechnePunkte (int *pPunkte, int iBonus)
    {
        *pPunkte += iBonus;
    }
    

    In der Funktion gibt es die Variable pPunkte, die eine Adresse enthält. Beim Aufruf wird die Adresse von iPunkte dort reinkopiert. Mit *pPunkte erhälst Du den Wert, der an der Adresse von iPunkte liegt, also iPunkte selbst.



  • Ja okay. Jetzt hab ichs kapiert.

    also wenn man als Prototypen angibt:

    [cpp]
    Void Funktion (*pPunkte, iBonus);
    [/cpp]

    ist *pPunkte bekannt für das Programm. Also Weiss der Compiler das eine Adresse übergeben werden muss/soll. Daraus schliesst man dann logischerweise das &iPunkte in *pPunkte gespeichert wird...



  • Nein, Du ordnest den Stern immernoch falsch zu 😉 - und das dort ist kein gültiger Prototyp, weil der Typ (int) fehlt.

    void function(int * pPunkte, int iBonus);
    

    Für das Programm bekannt ist pPunkte, nichts anderes. Nur, weil pPunkte ein Zeiger auf ein int (der Typ von pPunkte ist int 😉 ist, ist *pPunkte das an dieser Adresse liegende int. Dadurch ist *pPunkte aber keine eigene Variable, die heisst nach wie vor pPunkte, sondern einfach die Dereferenzierung eines Zeigers. Und die Adresse &iPunkte wird in pPunkte gespeichert, nicht in *pPunkte.



  • Mmh ja das is soweit klar. Also das mit dem Stern...Ist halt so ne gewöhnungssache denk ich mal...

    Aber eins ist mir imma noch nicht klar... Ich versuch das mal irgendwie durch kommentare im Quelltext zu verdeutlichen was ich meine:

    #include <iostream>
    
    using namespace std;
    
    // Prototypen
    
    void BerechnePunkte (int *pPunkte, int Bonus);
    // Hier ist jetzt das erste mal pPunkte und Bonus im Spiel
    // Aber ist ja eigendlich egal weil es würde ja reichen nur int,int zu schreiben // oder?
    
    int main() // Beginn der Main funktion
    {
        int iPunkte = 500; // iPunkte ist dem Programm jetzt bekannt
        int iBonus = 150; // iBonus ist dem Programm jetzt bekannt
    
       // Jetzt kann man mit den beiden Variablen arbeiten aber doch noch nicht mit 
       // *pPunkte oder pPunkte weil das ja hier auch nicht deklariert wurde
    
        // Punkte vor dem Funktionsaufruf anzeigen
        cout << "Punkte vor dem Funktionsaufruf: ";
        cout << iPunkte << endl; // Hier z.B. könnt ich nicht schreiben
    
        // cout << *pPunkte << endl;
    
        // Es wird die Funktion "BerechnePunkte" aufgerufen,
        // der als Parameter die ADRESSE der Variablen
        // "Punkte" übergeben wird sowie der Wert der Variablen
        // "Bonus"
    
        BerechnePunkte (&iPunkte, iBonus);
        // So hier wurde jetzt die Adresse von iPunkte übergeben
        // Aber woher weiss jetzt der Compiler oder das Programm
        // Das ich die Adresse in pPunkte speichern will? Das hab ich ja nirgendswo      
        // angegeben
    
        // Punkte nach dem Funktionsaufruf
        cout << "Punkte nach dem Funktionsaufruf: ";
        cout << iPunkte << endl;
    
        return 0;
    
    }
    
    void BerechnePunkte (int *pPunkte, int iBonus)
    {
        *pPunkte += iBonus; 
    
        // Hier benutze ich *pPunkte aber....anstatt iPunkte
        // Ist ja auch klar weil ich Adressen ja in Pointer speichere
        // Aber *pPunkte ist weder in der Main() noch in der BerechnePunkte()       //Funktion jemals deklaariert worden .. das einzigemal wo *pPunkte vorkommt ist
    // in den klammern als "int *pPunkte" parameter...zählt das denn als //deklaration? 
    }
    

    So hoffe jetz kommt nen bischen Licht in meine Frage 😃 Ist auch imma schwer sowas zu erklären irgendwie



  • Ja, eine Parameterliste dient hier als Deklaration 😉

    Plump gesagt läuft das in etwa so ab:
    Beim Aufruf der Funktion ist dem Compiler zunächst mal egal wie die Parameter in der Funktion heissen. Hier ist erstmal nur wichtig dass an erster Stelle eine Adresse auf ein Integer (int 😉 und an zweiter Stelle ein Integer (int) stehen muss. Das hast Du durch &iPunkte und iBonus erfüllt. Beim Sprung in die Funktion werden diese beiden Werte irgendwo (wo, ist erstmal nicht wichtig) abgelegt. Und anhand des Funktionskopfes weiss der Compiler nun "aha, ich soll den ersten abgelegten Parameter pPunkte und den zweiten iBonus nennen". Damit sind innerhalb der Funktion pPunkte und iBonus bekannt. iBonus ist hier ein eigener Name, der nur innerhalb der Funktion gilt und hat mit dem iBonus in main nur gemein, dass derselbe Wert drinsteht (weil Du beim Funktionsaufruf iBonus an die zweite Stelle gesetzt hast). Das sollte klar werden wenn Du den Funktionskopf mal änderst:

    void funktion(int * pPunkte, int iDarufzuaddieren)
    

    Dann wirst Du nämlich merken, dass der Compiler mit iBonus innerhalb der Funktion nichts mehr anzufangen weiss, weil die Variable nun iDraufzuaddieren heisst.



  • Jo... Jetzt ist auch meine Frage beantwortet 🙂

    Joa und was Intern passiert weiss ich so in etwa... Es wird ja eine Kopie auf dem Stack erzeugt die dann von der Funktion abgerufen wird und beim verlassen der Funktion gehts wieder auf den Stack und dann wieder in die Main.... Oder so ähnlich...also bei normalen Variablen wie bei iBonus jetzt....was man dann Call by Value nennt...

    Wenn daran was falsch ist könnt ihr mich ja gerne korrigieren

    Danke aber schonmal für die ganzen antworten



  • Gizm schrieb:

    ...
    ...Normalerweise macht man doch vorher immer noch eine Zuweisung:

    int iPunkte = 1000;
    int *pPunkte = NULL;
    
    pPunkte = &iPunkte;
    

    Oder hab ich da irgendwas nicht richtig verstanden....

    Aber genau das machst Du doch auch:

    Gizm schrieb:

    ...

    ...	BerechnePunkte (&iPunkte, ...
    

    ...

    Da passiert nichts anderes, als dass "pPunkte = &iPunkte" gesetzt wird.

    Vllt. verwirrt Dich nur die Tatsache, dass pPunkte diesmal nicht in main(), sondern in BerechnetPunkte() definiert ist. Ist aber trotzdem dasselbe.

    Gruß,

    Simon2.


Log in to reply