Warum und wie funktioniert ein char pointer?



  • Schreibe ich

    int * p = 10;
    

    Erhalte ich vom Compiler eine Fehlermeldung. Das geht nicht. Schreibe ich aber

    char * c = "C++";
    

    erhalte ich keine Fehlermeldung vom Compiler.

    Das ist für mich ein Paradox, wenn int * p nicht funktioniert, char *c hingegen funktioniert. int * p kann nur dann funktionieren, wenn eine Adresse (&-Operator) angegeben wird. Warum klappt es bei char * c ohne Angabe einer Adresse?



  • Offensichtlich hast du meine Antwort nicht ordentlich durchgelesen.
    Sonst wüsstest du nämlich, dass "" ein Stringliteral ist (const char[1]), und somit in einen Pointer zerfallen kann. Du versuchst hier zwei völlig unterschiedliche Dinge - ein char Literal wäre 'a'.

    int* p = 5; // Geht nicht
    char* c = 'c'; // Auch nicht
    


  • Weil "C++" ein Stringliteral vom Typ const char[] ist...



  • Mit "" erzeugst du einen Pointer, dessen pointee ein Char-Array mit Zeichen im ASCII-Wert und einem folgenden Null-Terminator ist.

    "C++"
    

    Ist also ein Zeiger auf folgendes:

    0xad4f849  67 // Das ist die Adresse von "C++" selbst!
    0xad4f84a  43
    0xad4f84b  43
    0xad4f84c  0
    

    Beispielsadressen (!).

    Wenn du mit einem Char-Array Pointer so zugreifst:

    const char* ptr = "C++";
    
    ptr[2]; //<<= Hier
    

    Verwandelt sich das zu

    *( ptr + 2);
    

    Und das heißt, dass man die Adresse von ptr um zwei erhöht (jetzt ist es 0xad4f84b) und dann dereferenziert.
    Deswegen kannst du auch sowas schreiben:

    2["C++"]
    
    "C++"[2]
    
    MeinPtr[2]
    
    2[MeinPtr]
    


  • Hacker schrieb:

    Mit "" erzeugst du einen Pointer, dessen pointee ein Char-Array mit Zeichen im ASCII-Wert und einem folgenden Null-Terminator ist.

    "C++"
    

    Ist also ein Zeiger auf folgendes:

    0xad4f849  67 // Das ist die Adresse von "C++" selbst!
    0xad4f84a  43
    0xad4f84b  43
    0xad4f84c  0
    

    Beispielsadressen (!).

    Nicht ganz. "C++" ist genau dieses Array und kein Zeiger drauf. Ein Stringliteral ist ein lvalue vom Typ const char[ n ] und kein const char* (Beweis: Lass dir mal sizeof("hello, world") ausgeben). Allerdings können Arrays in C++ implizit in Pointer auf das erste Element umgewandelt werden.



  • Erklär mir bitte, wieso das geht:

    *"C++"
    

    Und was genau der Unterschied zwischen den beiden ptr's ist (also den Typen der Identifier).

    const char ptr[5];
    

    und

    const char*  ptr;
    

    ist (außer, das man beim zweiten noch Speicherplatz zuweisen müsste).



  • Hacker schrieb:

    Erklär mir bitte, wieso das geht:

    Weil ein Array in einen Zeiger zerfallen kann? Ich denke das solltest du schon mal bemerkt haben. 🤡

    Hacker schrieb:

    Und was genau der Unterschied zwischen den beiden ptr's

    Es sind komplett unterschiedliche Typen? 😮

    "lol"++; // Autsch
    


  • Hacker schrieb:

    Erklär mir bitte, wieso das geht:

    *"C++"
    

    Weil das Stringliteral ein Array ist und das kann implizit in einen Pointer gewandelt werden...

    Hacker schrieb:

    Und was genau der Unterschied zwischen den beiden ptr's ist (also den Typen der Identifier).

    const char ptr[5];
    
    const char*  ptr;
    

    ist (außer, das man beim zweiten noch Speicherplatz zuweisen müsste).

    Das erste ist ein Array, das zweite ist ein Pointer. Frag mal was sizeof(ptr) dazu meint 😉



  • R- und L-Value ist das Stichwort. Einfach bisschen googeln! Jetzt hab ich es verstanden. Danke euch.



  • Bis jetzt habe ich verstanden, dass es mit den r- und l-values zusammenhängt. Wo ist definiert, dass const char [] l-value ist und z.B. ein int ein r-value? In C++ muss ja irgendwo definiert sein, dass const char [] ein l-value ist, also "hey, const char [], du bist ein r-value".



  • inc7 schrieb:

    Wo ist definiert, dass const char [] l-value ist und z.B. ein int ein r-value?

    Hmmm? int ist ein lvalue. const int ist ein rvalue.



  • LValues und RValues haben mit Typen nichts zu tun. Es gibt ints sowohl als LValues, als auch als RValues.

    int i = 42; // 42 ist ein RValue, i aber ein LValue
    

    Grundsätzlich gilt: Alles, was einen Namen hat, ist ein LValue. Umgekehrt ist aber nicht alles, was keinen Namen hat, ein RValue.



  • Dann würde sich aber deine Aussage mit folgendem Code wiedersprechen:

    cout << &"Test" << endl;
    cout << &10 << endl;
    

    Geändert wurde nur der Typ von string nach int.



  • Nein, das widerspricht sich eben genau nicht. Stringliterale sind LValues.



  • 314159265358979 schrieb:

    Es gibt ints sowohl als LValues, als auch als RValues.

    Kannst du mir Beispielcode zeigen, wo ein int als LValue verwendet wird?

    314159265358979 schrieb:

    Stringliterale sind LValues.

    Und wo ist das in C++ definiert? Irgendwo muss ja (in der Headerdateien oder so?) stehen "stringliterale = LValue"



  • inc7 schrieb:

    Kannst du mir Beispielcode zeigen, wo ein int als LValue verwendet wird?

    i = 42;
    

    inc7 schrieb:

    Und wo ist das in C++ definiert? Irgendwo muss ja (in der Headerdateien oder so?) stehen "stringliterale = LValue"

    camper wirds dir sicherlich gleich nachschlagen. Kannst ja im Standard nachsehen.



  • inc7 schrieb:

    Kannst du mir Beispielcode zeigen, wo ein int als LValue verwendet wird?

    🙄

    inc7 schrieb:

    314159265358979 schrieb:

    Stringliterale sind LValues.

    Und wo ist das in C++ definiert?

    Im Standard?

    ISO/IEC 14882 third edition [expr.prim.general] 5.1.1.1 schrieb:

    A literal is a primary expression. Its type depends on its form (2.14). A string literal is an lvalue; all other literals are prvalues.



  • *loschmich*



  • 314159265358979 schrieb:

    Grundsätzlich gilt: Alles, was einen Namen hat, ist ein LValue.

    Hm...

    enum { ich_bin_ein_rvalue };
    template<int ich_auch> struct s {};
    

    Und this ist auch ein r-value.



  • Dann eben: Alles, was einen Namen hat und Stück Speicher zur Laufzeit bezeichnet, hat einen Namen.


Anmelden zum Antworten