Zeiger Syntax



  • hallo freunde der programmierung

    ich würde nun endlich gerne mal mein kapitel zur zeiger syntax beenden. ich liebe zeiger und wende sie oft und gerne an. aber dennoch möchte ich nun endlich endgültige klärung über den syntax von zeigern haben. also:

    es gibt mir bekannt, zwei operatoren die man bei zeigern anwenden kann. da wäre der zeiger-operator selber (*) und der adress-operator (&). da man den syntax in verschiedenster form anwenden kann habe ich einige fragen die mir einfach bislang offen blieben. ich fange so gut wie möglich strukturiert an:

    der adress-operator (&)
    mit dem adress-operator kann man wie unscher erkennbar ist, die speicheradresse eines zeigers, einem anderen zeiger bzw. variablen zuweissen. nun gibt es aber auch referenzen, welche ja sehr zeiger ähnlich sind. wenn man als parameter z.b. eine referenz erwartet, heisst das dann also nichts anderes, als das man die speicheradresse eines zeiger erwartet?

    der zeiger-operator (*)
    dieser verwirrt mich am speziellsten. man kann damit zum einten einen zeiger dereferenzieren und zum anderen den inhalt eines zeiger, einem anderen übergeben, ist das korrekt?

    wenn ich jetzt z.B. nur den inhalt eines zeiger einem anderen zeiger zuweisen möchte, jedoch aber nicht eine referenz auf den zeiger, dann macht man das doch so oder?:

    *zeiger1 = *zeiger2;

    möchte ich das der einte zeiger auf den anderen zeigt (das nennt man glaube ich dereferenzieren, stimmt das?) dann geht das so oder?:

    zeiger1 = &zeiger2;

    speicher freigeben
    speicher freigabe ist ja nicht sonderlich schwer. man kann aber wie ich selber feststellen musste, sich bei zeigern als rückgabewert einer funktion schnell vertun. ich möchte speicher, der von einer funktion angefordert wird wieder freigeben, sobald die funktion mir das objekt übergeben hat. bevor ich jedoch den speicher wieder freigebe, möchte ich den inhalt es zeigers einem anderen zeiger übergeben, also eben keine referenz auf den zeiger, sondern den inhalt! das dachte ich mir sollte so gehen:

    int *Funktion2()
    {
    	int *variable = new int;
    	*variable = 200;
    	return variable; //wird hier nun der inhalt oder automatich
    					//der zeiger zurückgegeben? es wird ja weder * noch
    					//der & operator angewendet.
    }
    //---------------------------------------------------------------------------
    void Funktion1
    {
    	int *temp_variable = Funktion2();  //erhält nun eine referenz?
    									   //man nennt es dann also dereferenzieren?
    	int *variable = new int;
    	*variable = *temp_variable; //geschieht hier nun eine normale zuweisung oder
    							  //wird dereferenziert? oder was genau?
    
    	delete &temp_variable; //hier möchte ich nun den angeforderten speicher von
    						  //variable, der durch Funktion2 angefordert wurde,
    						  //wieder freigeben. gehört dau ein & oder * operator,
    						  //oder weder noch? wann gibt es ausnahmefälle und warum?
    }
    

    unterschiebe bei variablen und objekten
    gibt es bei der zeiger verwendung bei variablen und objekten für die speicher angefordert wird, einen unterchied beim zeiger syntax? ich glaube bei klassen wird * und & weniger verwendet, weil es dort klar ist, das sie instanziiert wurden, wenn der verwies-operator (->) eingesetzt wird. da objekt könnte ja auch auf dem stack angelegt worden sein, und nicht auf dem heap, dann sieht es mit dem syntax schon wieder anderst aus, oder?

    endlich licht ins dunkle
    also, grundsätzlich ist mir einfach teilweise die syntax anwendung von den beiden operatoren nicht ganz klar. wann und warum man jetzt doch den adress-operator und oder den zeiger-operator anwenden muss. eigentlich dachte ich es wäre logisch like:

    a) adress-operator: immer dann dran hängen wenn man explizit nur die adresse des speicherbereichs möchte oder eine referenz auf den zeiger legen möchte.

    b) zeiger-operator: immer dann dran hängen wenn man explizit den inhalt des zeigers einem anderen zeiger übergeben möchte. wenn zeiger "a" dann zerstört wird, lebt zeiger "b" jedoch weiter. ideal also, wenn man einen inhalt möchte und dann den alten speicher freigibt indem man den alten zeiger benutzt um den speicher dann freizugeben.

    ich möchte einfach nur endlich licht in der syntax anwendung und ggf. faustregeln nehme ich gerne an 🕶
    vielen dank.



  • Hallo erstmal 🙂

    also:

    jo die beiden operatoren gibt es.

    adress-operator kann man wie unscher erkennbar ist, die speicheradresse eines zeigers, einem anderen zeiger bzw. variablen zuweissen.

    nein, der &-operator hol die addresse einer variablen (zeiger sind auch variablen, ihr inhalt wird nur anders interpretiert). diese kannst du dann in einem zeiger speichern.

    eine referenz hingegen ist ein anderer name für eine variable. ist dem zeiger nicht unähnlich zumahl du beide bis auf die syntax und pointerarithmetik genauso benutzen kannst. eine referenz ist im prinzip ein "sicherer" zeiger, da er nicht auf 0 oder auf eine ungültige variable "zeigen" kann (außer als rückgabewert auf lokale variablen 😃 )

    mit dem *-operator kommst du an den inhalt des zeigers, also der wert der an der stelle im hauptspeicher steht, den der zeiger enthält.

    wenn ich jetzt z.B. nur den inhalt eines zeiger einem anderen zeiger zuweisen möchte, jedoch aber nicht eine referenz auf den zeiger, dann macht man das doch so oder?:
    
    *zeiger1 = *zeiger2;
    

    ja 🙂

    zeiger1 = &zeiger2;
    

    dereferenzieren ist, wenn man mit dem * auf den inhalt des zeigers zugreift, also auf die variable, auf die er zeigt.

    int *Funktion2()
    {
        int *variable = new int;
        *variable = 200;
        return variable; //wird hier nun der inhalt oder automatich
                        //der zeiger zurückgegeben? es wird ja weder * noch
                        //der & operator angewendet.
    }
    

    es wird der zeiger zurückgegeben.

    in der zweiten zeile kopierst du den wert 200 an die stelle wo der zeiger hinzeigt.
    mit dem return gibst du den wert (nicht den inhalt 🙂 ) des zeigers zurück.
    das ist die addresse wo unsere 200 steht

    void Funktion1
    {
        int *temp_variable = Funktion2();  //erhält nun eine referenz?
                                           //man nennt es dann also dereferenzieren?
        int *variable = new int;
        *variable = *temp_variable; //geschieht hier nun eine normale zuweisung oder
                                  //wird dereferenziert? oder was genau?
    
        delete &temp_variable; //hier möchte ich nun den angeforderten speicher von
                              //variable, der durch Funktion2 angefordert wurde,
                              //wieder freigeben. gehört dau ein & oder * operator,
                              //oder weder noch? wann gibt es ausnahmefälle und warum?
    }
    

    in der ersten zeile bekommst du den zeiger mit der 200 drin zurück.
    du kannst jetzt mit *temp_vaiable auf diesen wert zugreifen.
    löschen nicht vergessen -> der speicher ist dynamisch angefordert.

    in der dritten zeile holst du dir zuerst den inhalt von temp_vaiable (also 200)
    und kopierst sie dahin wo variable hinzeigt. also an eine andere stelle im speicher.

    achtung beim delete.
    delete erwartet ein zeiger.

    temp_variable ist schon ein zeiger und mit dem & holst du dir ein zeiger auf den zeiger 😃 der zeiger steht nämlich auch irgentwo im speicher.

    als eselsbrücke kannst du dir merken, dass man mit dem * operator einen stern "entfernt"
    aus einem "int**" macht er ein "int*" und aus einem "int*" wurde er ein "int" machen

    der & operator macht das umgekehrte er "fügt einen stern hinzu" (bildlich gesprochen)

    z.b.

    du hast einen "int *zeiger" und möchtest dort einen "int wert" reinkopieren ->

    *zeiger = wert;
    

    z.b.2

    du hast einen "int *zeiger" und möchtest das er auf "int wert" zeigt ->

    zeiger = &wert;
    

    zu den objekten:

    nein, wenn du einen zeiger hast ist es egal ob es sich um eine lokale / dynamische / variable / klasseninstanz handelt. d.h. an der syntax ändert sich nichts

    z.b.

    class test
    {
    };
    int main()
    {
        test t1; // lokal
        test *ptr1 = &t1
        test *ptr2 = new test;
        int var = 42;
        int *ptr3 = &var;
    
    // ptr1, ptr2 und ptr3 sind alles zeiger
    
        // inhalt von ptr3 verändern;
        *ptr3 = 350;
    
        // ptr1 "umbiegen"
        ptr1 = ptr2; // beide zeigen auf das selbe objekt
    
        delete ptr1; // deshalb ist es egabl über welchen zeiger man löscht
    }
    

    algemein:

    & wenn man die speicherstelle einer variablen oder eines objektes haben möchte

    * wenn man die speicherstelle über einen zeiger veränder möchte (oder nur lesen)

    und var->data ist identisch mit (*var).data
    aber die zweite methode sieht nicht schön aus, deshalb gibt es die erste

    hoffe ich konnte helfen

    mfg zeigerle



  • hallo zeigerle 🙂

    erstmal vielen dank für deine ausführliche hilfe. was das mit de delete **&**zeiger angeht: das heisst also ich kann mir eine faustregel machen, das ein zeiger der ein zeiger ist, definitiv ein zeiger ist und man da nicht weiteres bemerkbar machen muss? in anderen worten, ein auto ist und bleibt ein auto und kein fahrrad. somit entfällt also bei einem delete der adress-operator immer, ausnamhmslos?

    und nach deiner erklärung mit dem * operator sollte es nun auch definitiv klar sein. wir war es einfach manchmal nicht klar ob ich auf der linken und oder rechten seite nun den * operator brauche und wenn ja warum genau 🤡. also:

    Frage warum sollte auf der linken seite der zuweisung der * operator hinter der variablen stehen.
    Antwort damit sichergestellt wird und der compiler weiss, dass es eine wert zuweisung an die speicherstelle ist und keine zeiger zuweisung an die speicheradresse.

    Frage warum sollte auf der linken seite der zuweisung der * operator nicht hinter der variablen stehen.
    Antwort damit sichergestellt wird und der compiler weiss, dass es eine zeiger zuweisung an die speicheradresse ist und somit beide variabeln auf den gleichen speicherbereich zeigen.

    dann noch etwas generelles: stimmt folgendes beispiel?

    //speicher für pointer dynamisch anfordern.
    	int *pointer = new int;
    
    	//pointer2 al zeiger deklarieren.
    	int *pointer2;
    	//nicht-zeiger variable
    	int stack_var;
    
    	//das hier geht und an die speicherstelle von pointer
    	//wird der wert, der nicht-zeiger variable, zugewiesen.
    	*pointer = stack_var;
    
    	//für pointer2 wurde zwar kein speicher angefordert was aber nichts macht
    	//da pointer2 nun einfach auf den speicher von pointer zeigt(!)
    	pointer2 = pointer;
    
    	//der wert vom speicherbereich der zeiger-variable wird nun über den zweiten
    	//zeiger (pointer2) verändert
    	*pointer2 = 200;
    
    	//geht nicht weill 200 kein zeiger ist ;-)
    	pointer2 = 200;
    
    	//das geht nicht weil pointer nicht auf den stack zeigen kann
    	//da die variable stack_var kein zeiger ist und somit nicht auf dem heap
    	//hinterlegt ist. oder sind auf dem heap nur alle dynamisch angeforderte
    	//variablen und objekte? können zeiger auch auf dem stack sein?
    	pointer = stack_var;
    
    	//das geht ohne probleme. hier wird also der normalen variable
    	//einfach der wert von (in diesem fall pointer) zugewiesen
    	stack_var = *pointer2;
    
    	//DAS GEHT NICHT WEIL???????????
    	//HIER WOLLTE ICH DER NORMALEN VARIABLE DIE ADRESSE VON (pointer in dem fall)
    	//ZUWEISEN
    	stack_var = &pointer2;
    
    	//DAS GEHT NICHT WEIL???????????
    	//HIER WOLLTE ICH AN DER PEICHERSTELLE (pointer in dem fall)
    	//DIE ADRESSE ALS WERT VON POINTER AN POINTER2 ZUWEISEN
    	*pointer2 = &pointer;
    	//DAS GLEICHE....
    	pointer2 = &pointer;
    
    	//speicher wieder freigeben.
    	delete pointer;
    	pointer = NULL;
    

    stimmt das soweit? siehe kommentare 😋
    nur bei den beiden letzten varianten bin ich nicht ganz sicher warum nicht.



  • zeigerle, hilfe 😋

    //TempObjekt sollte nun auf das
    		//Objekt zeigen, welches als adresse der methode
    		//von Objekt2 zurückgeliefert wird
    		TempObjekt = Objekt2->Methode();
    
    		//Objekt sollte nun der wert von TempObjekt übergeben werden
    		*Objekt = *TempObjekt;
    
    		//UND HIER HAKT ES! HIER SOLL DER DYNAMISCH ANGEFORDERTE SPEICHER DES OBJEKT
    		//WELCHES VON DER METHODE OBEN ANGELEGT WIRD, WIEDER FREIGEGEBEN WERDEN.
    		//ABER IRGENDWIE HÄNGT AUCH OBJEKT DA NOCH MIT DRAN!? WEIL BEI VERWENDUNG VON
    		//OBJEKT IM PROGRAMM, GIBT ES EINE EXCEPTION.
    		delete TempObjekt;
    		TempObjekt = NULL;
    

    ich dachte nun hätte ich es, aber siehe...



  • wenn ich nun eben den letzten code auf folgendes ändere:

    [cpp]delete **&**TempObjekt[/cpp]

    funktioniert es wunderbar. deswegen auch meine frage zu delete und adress-operator. was genau mache ich falsch oder doch richtig?



  • jetztaber schrieb:

    hallo zeigerle 🙂

    Frage warum sollte auf der linken seite der zuweisung der * operator hinter der variablen stehen.
    Antwort damit sichergestellt wird und der compiler weiss, dass es eine wert zuweisung an die speicherstelle ist und keine zeiger zuweisung an die speicheradresse.

    Frage warum sollte auf der linken seite der zuweisung der * operator nicht hinter der variablen stehen.
    Antwort damit sichergestellt wird und der compiler weiss, dass es eine zeiger zuweisung an die speicheradresse ist und somit beide variabeln auf den gleichen speicherbereich zeigen.

    Also wenn der * operator hinter einer Variable steht dann ist das eine multiplikation und hatt nichts mit pointer oder Adressen zu tun.

    dann noch etwas generelles: stimmt folgendes beispiel?

    //speicher für pointer dynamisch anfordern.
    	int *pointer = new int;
    
    	//pointer2 al zeiger deklarieren.
    	int *pointer2;
    	//nicht-zeiger variable
    	int stack_var;
    
    	//das hier geht und an die speicherstelle von pointer
    	//wird der wert, der nicht-zeiger variable, zugewiesen.
    	*pointer = stack_var;
    
    	//für pointer2 wurde zwar kein speicher angefordert was aber nichts macht
    	//da pointer2 nun einfach auf den speicher von pointer zeigt(!)
    	pointer2 = pointer;
    
    	//der wert vom speicherbereich der zeiger-variable wird nun über den zweiten
    	//zeiger (pointer2) verändert
    	*pointer2 = 200;
    
    	//geht nicht weill 200 kein zeiger ist ;-)
    	pointer2 = 200;
    
    	//das geht nicht weil pointer nicht auf den stack zeigen kann
    	//da die variable stack_var kein zeiger ist und somit nicht auf dem heap
    	//hinterlegt ist. oder sind auf dem heap nur alle dynamisch angeforderte
    	//variablen und objekte? können zeiger auch auf dem stack sein?
    	pointer = stack_var;
    

    Ob heap oder stack ist hier völlig. "pointer = stack_var;" geht aus dem selben Grund nicht wie "pointer2 = 200;" weil stck_var kein pointer ist.
    "pointer = &stack_var;" so gehts, mit & holst du dir die Adresse von stack_var.

    //das geht ohne probleme. hier wird also der normalen variable
    	//einfach der wert von (in diesem fall pointer) zugewiesen
    	stack_var = *pointer2;
    
    	//DAS GEHT NICHT WEIL???????????
    	//HIER WOLLTE ICH DER NORMALEN VARIABLE DIE ADRESSE VON (pointer in dem fall)
    	//ZUWEISEN
    	stack_var = &pointer2;
    

    stack var ist vom typ int, &pointer2 vom typ int** also pointer auf pointer auf int. stack_var erwartet einen Integer, ohne trickserei kann du hier keinen pointer zuweisen.

    //DAS GEHT NICHT WEIL???????????
    	//HIER WOLLTE ICH AN DER PEICHERSTELLE (pointer in dem fall)
    	//DIE ADRESSE ALS WERT VON POINTER AN POINTER2 ZUWEISEN
    	*pointer2 = &pointer;
    	//DAS GLEICHE....
    	pointer2 = &pointer;
    

    pointer2 ist von typ int* wenn du jetzt ein * davor setzt bekommst du einen int. pointer ist auch vom typ int* du setzt ein & davor also bokommst du einen Zeiger auf einen int Zeiger also int**. int und int** kannst du nicht einander zuweisen.

    Bei der zweiten Zeile hast du pointer2 vom typ int* und pointer ist auch vom typ int* jetzt setzt du aber & davor also hast du wieder einen pointer auf pointer von int. int** zuweisen an int* geht nicht.

    Das einzige was hier Sinn macht ist entweder "pointer2 = pointer" du lässt pointer2 auf die gleiche Stelle wie pointer zeigen oder "*pointer2 = *pointer"
    du kopierst den Wert auf den pointer zeigt an die Stelle an die pointer2 zeigt.



  • jetztaber schrieb:

    zeigerle, hilfe 😋

    //TempObjekt sollte nun auf das
    		//Objekt zeigen, welches als adresse der methode
    		//von Objekt2 zurückgeliefert wird
    		TempObjekt = Objekt2->Methode();
    
    		//Objekt sollte nun der wert von TempObjekt übergeben werden
    		*Objekt = *TempObjekt;
    
    		//UND HIER HAKT ES! HIER SOLL DER DYNAMISCH ANGEFORDERTE SPEICHER DES OBJEKT
    		//WELCHES VON DER METHODE OBEN ANGELEGT WIRD, WIEDER FREIGEGEBEN WERDEN.
    		//ABER IRGENDWIE HÄNGT AUCH OBJEKT DA NOCH MIT DRAN!? WEIL BEI VERWENDUNG VON
    		//OBJEKT IM PROGRAMM, GIBT ES EINE EXCEPTION.
    		delete TempObjekt;
    		TempObjekt = NULL;
    

    ich dachte nun hätte ich es, aber siehe...

    Ohne zu wissen was Methode() zurück gibt und was TempObjekt für eine Variable ist kann man hier eigentlich nichts dazu sagen.



  • Hallo 😃 😃

    ich gehe mal davon aus, dass die Methdode() einen zeiger auf einen dynamisch allokierten speicher liefert. da ich den typ des zeigers nicht kenne nennen wir
    ihn mal T.

    TempObjekt = Objekt2->Methode();
    

    damit das funktioniert muss TempObjekt vom typ T* (zeiger auf den typ T) sein.

    *Objekt = *TempObjekt;
    

    Objekt muss ein weiterer T* zeiger sein. desweiteren muss er schon auf eine variable zeigen (dynamisch oder loakl ist egal).

    mit *TempObjekt holst du dir die variable vom typ T (ohne stern) und kopierst sie an die stelle wo Objekt hinzeigt. das heißt, das Objekt oder der wert existiert jetzt 2-mal.

    delete TempObjekt;
    TempObjekt = NULL;
    

    jetzt löscht du den inhalt von TempObjekt, also den speicher, den die methode Objekt->Method() zurückgegeben hat. der inhalt von *Objekt ist davon nicht betroffen. danach setzt du de zeiger auf 0, da er sonst auf einen schon freigegeben speicherbereich zeigen würde.



  • edit :

    ja zeiger können auf dem stack sein. desweiteren ist es egal ob der zeiger auf den stack zeigt oder auf den heap. sofern du nicht vergisst, den heap-speicher wieder freizugeben, kannst du beide bereiche genauso nutzen (ausnahme rückgabe). denn auch der stack liegt im selben hauptspeicher und nicht im drucker 🙂



  • hallo jungs und danke erstmal 😋

    Tanren

    Also wenn der * operator hinter einer Variable steht dann ist das eine multiplikation und hatt nichts mit pointer oder Adressen zu tun.

    mit hinter der variable habe ich mich vertan. ich meinte damit eigentlich davor. also davorvariable.

    stack var ist vom typ int, &pointer2 vom typ int** also pointer auf pointer auf int. stack_var erwartet einen Integer, ohne trickserei kann du hier keinen pointer zuweisen.

    aber warum kann man einer normalen variable keine adresse zuweisen? bedeutet die zuweisung einer adresse auch gleich das ein zeiger zugewiesen wird?

    Zeigerle

    ich gehe mal davon aus, dass die Methdode() einen zeiger auf einen dynamisch allokierten speicher liefert. da ich den typ des zeigers nicht kenne nennen wir
    ihn mal T.

    genau. Objekt und TempObjekt sind von einer klasse. für beide würde separater speicher allokiert.

    der inhalt von *Objekt ist davon nicht betroffen

    in meinem beispiel aber schon 😕 es funktioniert wirklich nur wenn ich
    delete **&**TempObjekt; verwende. die methoden definition bzw. deklaration sieht so aus:

    DieKlasse* AndereKlasse::Methodenname()
    {
        Objekt = new Objekt();
        //....code...
        return Objekt;
    }
    

    DieKlasse ist also der typ von Objekt und TempObjekt. AndereKlasse ist einfach eine andere klasse von wo aus gearbeitet wird. also vonwo ->Methode(); kommt.



  • und noch ein paar sachen dann sind wir durch 🙂

    also:

    1. was genau bedeutet nun referenzieren und dereferenzieren?
    2. wie nennt man eigentlich den zugriff auf nicht allokierte objekte? also so Objekt.Attribut; bei allokierten objekten wäre das ja "zugriff über verweisoperator ->".
    3. wenn eine funktion als parameter z.b. int** erwartet, bedeutet das was genau? das sie einen zeiger auf einen zeiger erwartet wahrscheinlich oder? aber wie genau ist das zu verstehen? z.b. sowas?:
    int *zeiger1 = new int;
    int *zeiger2 = new int;
    
    zeiger2 = &zeiger1;
    

    dann verstehe ich aber nicht ganz wo da nun der sinn bzw. der unterschied ist. so ist zeiger2 ja ein zeiger der von einem zeiger die adresse bekommt, aber was it daran nun anderst als bei zeiger2 = zeiger? hier zeigt nun zeiger2 auf den gleichen speicherbereich wie zeiger1. der unterschied ist meiner meinung nach also nur, das bei ersterem, zeiger2 nicht auf den speicherbereich von zeiger1 zeigt, sondern das zeiger2 die adresse von zeiger1 bekommt.

    das wiederum bedeutet für mich: es gibt einen unterschied zwischen "auf einen speicher bereich zeigen" und "eine speicheradresse erhalten" oder nennt man es "auf die speicheradresse zeigen" weil irgendwie ist für mich das, dass gleiche. so ungefähr 😉



  • Huhu 🙂

    aber warum kann man einer normalen variable keine adresse zuweisen? bedeutet die zuweisung einer adresse auch gleich das ein zeiger zugewiesen wird?

    ja man kann einer normalen variable einen zeiger zuweisen.

    zum verständnis:

    auch ein zeiger ist im grunde eine zahl, auf 32-bit systemen entsprechend 4 byte groß und damit ein int. er ist kein misteriöser datentyp und in ihm lässt sich jeder wert speichern. wenn man das typsystem ungeht kann man damit auch rechnen.

    int *zeiger = reinterpret_cast<int *>(4207);
    // zeiger enthält jetzt den wert 4207. allerdings gibt es einen fehler wenn
    // du den zeiger dereferenzierst
    *zeiger = 0; // FALSCH !! FEHLER!!
    

    auf dem selben wege kannst du dir auch angucken, wo im speicher deine variablen stehen.

    cout << reinterpret_cast<int>(&var) << endl;
    

    den cast braucht man um eben aus einem int* ein int zu machen, sprich das typsystem zu umgehen.

    so zu 1:

    dereferenzieren : mithilfe von * oder -> das objekt/variable eines zeigers auslesen/verändern

    referenzieren : ka 😕 😕 glaube das selbe bin aber nicht sicher

    2 : ganz einfach zugriff

    int a = 5;
    int *ptr = &a;
    *ptr = 9; // ich "greife" zu
    

    3 : nein, das konstrukt da ist tödlich. beide zeiger sind vom typ int*.
    in der dritten zeile weißt du einem int* ein int** zu -> böse -> fehler.

    mithilfe eines zeigers gibst du der funktion die möglichkeit, die originaldaten zu verändern.
    mit einem zeiger auf einen zeiger kannst du den originalzeiger verändern.

    wenn zum beispiel der rückgabewert nicht mehr frei ist (durch bool z.b. der angibt ob die funktion erfolgreich war)

    z.b.

    // erstes beispiel
    int *func()
    {
        return new int;
    }
    int *a = func();
    
    // zweites beispiel, die funktion nutzt den rückgabewert um zu
    // zeigen ob ein fehler auftrat
    bool func2(int **a)
    {
        int *mem = new int[100000000];
        if (mem)    // genug speicher da?
        {
            *a = mem;
            return true;
        }
        return false;
    }
    int *a;
    bool erfolg = func2(&a);
    if (erfolg)... // in a ist jetzt der allokierte speicher
    

    eine andere möglichkeit wäre ein 2D-array
    [cpp]
    int **array = new int *[5]; // hier holen wir speicher für 5 zeiger
    for (int i = 0; i < 5; ++i)
    array[i] = new int[5]; // und hier den speicher selber
    [/cpp]

    das sähe dann so aus

    array ---> | [] [] []
                  | [] [] [] // die zeile wäre array[1] 
                  | [] [] [5] // und die zelle wäre array[2][2]
    

    nein da gibt es keinen unterschied. um auf einen speicherbereich zu zeigen muss man seine speicherstelle haben (in einem zeiger).



  • okay vielen dank. man muss aber nicht explizit den zeiger-operator anwenden wenn man einem zeiger einen wert zuweisen will, wenn dieser wert nicht von einem zeiger kommt oder? also:

    //zeiger-wert von einen anderen zeiger-wert übergeben
    *zeiger2 = *zeiger1;
    
    //zeiger-wert konstant verändern
    *zeiger2 = 200;
    

    ich habe schnell eine skizze gezeichnet mit dem nun gelernten. stimmt das nun soweit?
    Bitte hier klicken



  • jop so ist es richtig - bis auf die letzte zeile. wenn du das kompiliert bekommst das würde es auch richtig funktionieren, nur du hast hier ein typenproblem.

    versuche es mal so ➡

    int *zeiger1 = new int;
    int *zeiger2 = new int;
    
    // [...]
    
    int **zeiger3;
    
    zeiger3 = &zeiger1; // das klappt jetzt
    

    das problem liegt darin das zeiger1 ein int* ist. mit dem & operator bekommst du einen int** um den zu speichern sollte man auch einen int** benutzen 😃
    (es sei den man nimmt C oder assembler)

    aber der rest ist richtig 👍



  • zeigerle schrieb:

    Huhu 🙂

    so zu 1:

    dereferenzieren : mithilfe von * oder -> das objekt/variable eines zeigers auslesen/verändern

    referenzieren : ka 😕 😕 glaube das selbe bin aber nicht sicher

    Also referenzieren ist einfach das Gegenteil von dereferenzieren nämlich mit dem & operator die Adresse einer Variable holen.



  • also habt vielen dank ihr zwei. zu guter letzt noch eins: sowas wie mehr als einen zeiger auf einen zeiger gibt es aber nicht oder? würde auch keinen sinn machen. auch wenn mein compiler sowas zwar compilieren kann:

    int *******a;



  • doch das gibt es

    ich musste es sogar mal benutzen

    szenario:

    ein dynamisches 2D spielfeld von zeigern auf bestimmte blöcke. die ladefunktion bekam die adresse eines solchen zeigers um ihn auszufüllen. die schnittstelle sah so aus (kein witz, und sie hat sogar funktioniert)

    bool LoadField(const std::fstream &f, CBlock **** feld, unsigned x, unsigned y, HINSTANCE dll);
    

    habe es dann aber durch

    vector<vector<Block*> > & feld;
    

    ersetzt es ist deutlich einfacher so

    aber es funktionert auch in der praxis (ist aber seeeehr unschön)


Anmelden zum Antworten