Müssen Pointer Pointer immer auf Pointer zeigen ?



  • SeppJ schrieb:

    Doch, sicher. C(99)-Standard, 6.3.2.3, 5-6. Leider weigert sich der pdf-Reader hier am Rechner mir den Text aus meiner Fassung des Dokuments auszuschneiden. 😞
    Es wird dort jedenfalls explizit Daten- zu Datenzeigerkonvertierung erlaubt, sofern das Alignment passt (ansonsten UB). Der nächste Absatz erlaubt das gleiche für Funktionszeiger.

    Ja sicher ist die Konvertierung erlaubt, aber da steht nichts davon, dass sie implizit durchgeführt wird. Im Gegenteil, in 6.5.4 steht "Conversions that involve pointers, other than where permitted by the constraints of 6.5.16.1, shall be specified by means of an explicit cast."

    6.5.16.1 ist auch nicht sehr ergiebig, dort werden folgende impliziten Konvertierungen zugelassen:
    * zwischen Zeigern auf kompatible Typen
    * wenn ein void-Zeiger dabei ist
    * Nullzeigerkonstanten nach Zeigertyp
    * Zeiger nach _Bool

    Kompatibilität zwischen Typen ist eine sehr eng gestrickte Äquivalenzrelation, auf keinen Fall sind alle Typen kompatibel.



  • Also ich gestern schlafen gegangen bin dachte ich wüsste wenigstens irgendwas. Ich weiß gar nichts. Möchte aber wenigstens die ultra Basics können das ich in meinem Übungen weiter komme.

    1.) Das einzige was ich vielleicht verstanden habe

    int i;
    // Ein facher Zeiger sollte immer auf Variablen zeigen
    int* p1 = &1;
    // Wenn ich jetzt so blöd bin 😉 und mir nen Pointer Pointer bauen will, dann muss // sollte ? ich diesen auf einen normalen Pointer zeigen lassen
    int** p2 = &p1;
    // Und zum letzten mal weil so schön ist. Ich baue mir einen *** und dieser muss ? auf einen ** zeigen
    int***p3 = &p2

    Ich hoffe wenigstens das passt... wenn man das in ein Schema reinbringen.

    * zeigt auf Adresse von Variablen
    ** zeigt auf Adresse von *
    *** zeigt auf Adresse von ** usw

    Die kleine Zwischenfrage drängt sich auf warum man wirklich ** braucht. Sobald ich eine Variable ändern will ( keinen Pointer) schreibe ich
    Typ foo* = &Zu_veränderende_Variable ... und zack kann ich sie ändern ? Warum also den Aufwand antun einen ** zu erstellen auf einen * zeigen zu lassen und über diesen dann die Variable zu ändern ? Ganz kurze Antwort für sau blöde User bitte.

    Und hier ein kleines Beispiel von mir:

    char* p = "Hello";
    char** pp = &p;
    
    *p = "Funktioniert"; //klappt
    pp[0] = "Funktioniert"; //klappt auch
    //Hier der Versuche auf einzelne Elemente des Feldes zuzugreifen.
    printf("%c",**p); // Fehler Erhoffte mir 'F'
    printf("%c",p[0][1]); // Fehler Erhoffte mir 'u'
    

    p.s Schaue mir das Beispiel von oben noch genauer an. Aber habe wenig Hoffnung 😉



  • p ist nur ein einfacher Zeiger.

    Und du benutzt ihn bei printf wie einen Doppelzeiger.
    Schreib da pp hin und es passt.

    Das *p = "Funktioniert"; ist auch falsch

    char *p = "Funktioniert"; // ist richtig, da es die Varialendefinition ist
    .. 
    *p  = "Funktioniert nicht"; // ist falsch
    p = "Richtig" ; // ist richtig
    


  • ** sind natürlich gerechtfertigt, da reicht ein Blick auf

    int main(int argc,char**argv)
    

    ** repräsentiert hier eine String-Liste.
    Das kannst du dann endlos weiterführen:
    wie sieht ein Zeiger auf eine Stringliste aus? (z.B. für die Übergabe einer Stringliste an eine ändernde Funktion)

    char ***
    

    Und schon hast du sogar 3 Ebenen.



  • [quote="DirkB"]
    Schreib da pp hin und es passt.
    /quote

    Danke, hab den falschen Zeiger genommen.2 Mal nämlich. Habe mich bisschen rumgespielt mit den Pointern. Danke soweit gehts eigentlich bis auf zwei Sachen.

    char* p = "Hello";
    char** pp = &p;
    
    //Erste Frage
    printf("%c\n",**pp); //Gibt erstes Zeichen Haus.
    pp++; // Möchte den Pointer um eine Speicherstelle erhöhen um auf 'e' zu kommen Fehler
    printf("%c\n",**pp); //Hier sollte 'e' rauskommen
    
    //2 Frage
    printf("%c\n",**pp+1) //Erhöht den ASCII Wert um 1ns ... anstatt das er die nächste Stelle ausgeben würde :(
    

  • Mod

    1. Pointerarithmetik ist dir bekannt?

    int werte[] = {1,2,3};
    printf("%d", *(werte+1));
    

    Ergibt "2", anstatt, so wie du es vielleicht vermuten würdest, irgendwelchen Datenmüll.
    2. Operatorpriorität.



  • //2 Frage
    printf("%c\n",**pp+1) //Erhöht den ASCII Wert um 1ns ... anstatt das er die nächste Stelle ausgeben würde 😞
    **pp ist ja auch ein char. So wie es bei der Definition steht.
    Und was erwartest du bei c+1?

    char c, *p, **pp; // c, *p und **pp sind jeweils char
    p und *p sind Zeiger auf char

    Noch als Anmerkung:
    Wenn du schreibst
    char* p, c; dann ist p ein Zeiger und c ein char, weil es das gleiche ist wie
    char *p, c;



  • SeppJ schrieb:

    1. Pointerarithmetik ist dir bekannt?

    int werte[] = {1,2,3};
    printf("%d", *(werte+1));
    

    Ergibt "2", anstatt, so wie du es vielleicht vermuten würdest, irgendwelchen Datenmüll.

    Ja ist mir Bekannt sonst würde ich nicht auf die Idee kommen das sowas überhaupt geht. Dein Beispiel hilft mir bei meinem Problem nicht weiter.

    char* p = "Hello";
    char** pp = &p;
    
    printf("%c\n",**pp); 
    //Was muss hierher damit das unten das Zeichen e ausgeben wird  ?
    // **(pp+1); oder *(pp+1) geht schon mal nicht :(.   
    printf("%c\n",**pp); // hier soll e gedruckt werden
    

    thx für 2 🙂


  • Mod

    Bullz schrieb:

    SeppJ schrieb:

    1. Pointerarithmetik ist dir bekannt?

    int werte[] = {1,2,3};
    printf("%d", *(werte+1));
    

    Ergibt "2", anstatt, so wie du es vielleicht vermuten würdest, irgendwelchen Datenmüll.

    Ja ist mir Bekannt sonst würde ich nicht auf die Idee kommen das sowas überhaupt geht. Dein Beispiel hilft mir bei meinem Problem nicht weiter.

    Wenn ein Zeiger auf Integer bei Erhöhung auf den nächsten Integer gesetzt wird, auf was wird dann wohl ein Zeiger auf Zeiger auf char bei Erhöhung gesetzt?



  • Wie in der Schule 😉

    Den nächsten Char was er bei mir aber nicht tut.

    Ich könnte die scheiß Pointer vom 10 Stock gerade werfen.

    **(pp+1); schaut doch eh recht gut aus... warum macht der Compiler nicht das was ich will ?


  • Mod

    Bullz schrieb:

    Den nächsten Char was er bei mir aber nicht tut.

    Was daran liegt, dass diese Antwort falsch ist.

    int *i;
    char **c;
    ++i;  // Zeigt auf den nächsten int
    ++c;  // Du sagst: Zeigt auf den nächsten char
    

    Ist das nicht inkonsequent? Ich schreibe es mal anders:

    typedef int my_int_type;
    typedef char* my_char_ptr_type;
    
    my_int_type *pointer_to_my_int_type;
    my_char_ptr_type *pointer_to_my_char_ptr_type;
    
    ++pointer_to_my_int_type;  // Zeigt auf den nächsten my_int_type
    ++pointer_to_my_char_ptr_type; // Worauf zeigt dies?
    
    **(pp+1); schaut doch eh recht gut aus... warum macht der Compiler nicht das was ich will ?
    

    Du musst dich wieder fragen, welchen Wert du um 1 erhöhen willst. **p wolltest du wohl nicht um 1 erhöhen, denn das war der erste char selbst. pp willst du wohl auch nicht um eins erhöhen, denn das ist der Zeiger, der auf den anderen Zeiger zeigt, der auf den ersten char zeigt.

    warum macht der Compiler nicht das was ich will ?

    Der Computer macht ganz genau das, was du ihm sagst. Wenn du ihm etwas anderes sagst, als du willst, dann macht er folglich nicht das, was du willst. Die Schuld liegt aber da drin, dass du nicht richtig ausdrückst, was du möchtest.



  • Bullz schrieb:

    **(pp+1); schaut doch eh recht gut aus... warum macht der Compiler nicht das was ich will ?

    Weil der Compiler macht, was du ihm sagst. 😃
    Mit *(pp+1) schaltest du auf den nächsten Zeiger und greifst dann auf das Zeichen zu.
    pp zeigt dann nicht mehr auf p, sondern daneben. Und da ist kein gültiger char
    .

    JEtzt fehlt noch die dritte Möglichkeit: *(*p+1)



  • vielen dank für die Mühe an euch beiden. Wäre auf das nie gekommen. Habe diese Syntax noch bei keinem Beispiel gesehen. Habe jetzt mal alles notiert und werde weitermachen. Bin wahrscheinlich zu blöd um diese einwandfrei zu verstehen 😉

    Die letzte wichtige Erkenntnis zum Schluss war noch

    int** a;
    **a ist vom typ int // das war mal nicht schlecht 😉

    char c = 'c'
    char* p1 = &c;
    char** p2 = &p1;
    
    **p2 = 'x'; // Das ist sinnvoll. Hoffe ich jedenfalls 
    *p2 = 0x1234; //sinnlos da irgendwo hinzeigt ?
    p2 = 0x9876; //sinnlos da irgendwo hinzeigt ?
    

    p2 -> p1 ->c

    &p2 irgendwo
    value p2: 0x500

    &p1 0x500
    value 0x200

    &i 0x200
    value char

    Wenn ich jetzt schreibe

    *p2 = 0xf00

    schaut das dann nicht folgenderweise aus

    &p2 irgendwo
    value p2: 0x500

    &p1 0x500
    value 0xf00

    &i 0x200
    value int

    Irgendwie seh ich da keinen Sinn dahinter. Zerstöre ich mir dadurch doch nur das mein p1 nicht mehr auf &i zeigt ...


  • Mod

    Im großen und ganzen richtig (Die Syntax bei "a**" ist falsch. "**a" muss das heißen).

    Bullz schrieb:

    Irgendwie seh ich da keinen Sinn dahinter.

    Du hast korrekt erkannt, dass es selten sinnvoll ist, einem Zeiger direkt einen Zahlenwert (außer vielleicht 0) zuzuweisen.



  • ich hab schon bissi java Programmiert aber ich bin noch nie wo so lange dran gesessen wie an den Pointern...

    Mit Feldern kann ich wesentlich einfacher arbeiten... sobald irgendetwas komplett neues auf mich zukommt steh ich wieder blöd da.

    Würde ja auf diesen Teil gern verzichten. Komme mit der Feldnotation wesentlich besser zurecht aber dann werd ich kaum fremden Code lesen können.

    int main(int argc,char* argv[])
    {
    //....
    // Leicht verständlich und funktioniert bestens
    switch (argv[2][0]) 
    // Durch reines rumprobieren ohne Hirn
    switch (**(argv+2))
    // 
    {
    case '+':
    /...
    }
    }
    

    Was wäre aber wenn ich auf argv[2][1] mit Pointernotation zugreifen wollen würde ?
    Meine vielversprechenden weltenverbesserenden Ansatz
    switch(*argv+1*(argv+2));

    Das beste ist er frisst es sogar. Bekomme aber Fehlermeldung:
    Ungültiger Operanden für binäres * (haben int und char**)



  • *argv+1*(argv+2)); 
           ^
           Der * ist der Multiplikationsoperator. Der braucht zwei Operanden. Daher binär
    Die 1 ist ein int und (argv+2) ist char**
    

    `

    argv+2 ist wie argv[2] (ein char)

    *(*argv+2) ist argv[2][0] (ein char. Es wird auch zweimal dereferenziert (mit zwei *))

    *((*argv+2)+1) ist argv[2][1]`



  • danke... jetzt verstehe ich langsam wie das mit den Pointern geht. Ist ja wie mit Feldern nur ein wenig verkehrt gedacht ...

    Trotzdem funktioniert dein Statement nicht bei mir

    switch(argv[2][1])  // funktioniert
    switch(*((*argv+2)+1)) // dont work
    


  • Schäm.
    Da waren die Klammern falsch 🙄
    `(argv+2) ist wie argv[2] (ein char)

    **(argv+2) ist argv[2][0] (ein char. Es wird auch zweimal dereferenziert (mit zwei *))

    ((argv+2)+1) ist argv[2][1]`


Anmelden zum Antworten