Warum und wie funktioniert ein char pointer?



  • Alles was einen Namen hat, hat einen Namen? 🙄



  • *ist ein LValue



  • Hmm, jetzt bin ich verwirrt!

    const int MeinName(0);
    

    Also, nach PI's Logik ist der Wert von MeinName kein solcher, der im Speicherplatz vorhanden ist, oder wat? MeinName ist doch ein Rvalue.


  • Mod

    Lvalues/Rvalues sind Ausdruckskategorien.
    Ein Bezeichner ist weder ein L- noch ein Rvalue.
    Ein (primärer) Ausdruck, der durch einen Bezeichner geformt wird, ist ein L- oder Rvalue, je nach Art des Bezeichners.



  • @Hacker: Natürlich ist das ein LValue, und natürlich hat der int auch Speicher. Dass der Compiler ihn wegoptimiert, ist ne andere Sache. Aber versuch doch mal, die Adresse davon rumzureichen, dann wird der int mit ziemlich großer Sicherheit nicht wegoptimiert.


  • Mod

    Hacker schrieb:

    Hmm, jetzt bin ich verwirrt!

    const int MeinName(0);
    

    Also, nach PI's Logik ist der Wert von MeinName kein solcher, der im Speicherplatz vorhanden ist, oder wat? MeinName ist doch ein Rvalue.

    Das ist zunächst mal eine Deklaration (und Definition), und kein Ausdruck. Also auch kein L- oder Rvalue. Und MeinName ist bloß der Bezeichner, der hier deklariert wird, nicht mehr und nicht weniger.
    Jede darauf folgende Verwendung dieses Bezeichners wäre ein Lvalue.



  • Das wird ja immer komplizierter. Inzwischen bin ich verwirrter als vorher. Ich versuche mal ganz konkret zu Fragen.

    Das Ausführen folgender Codezeile funktioniert fehlerfrei. Auf der Konsole wird die Adresse des Strings angezeigt.

    cout << &"Test" << endl;
    

    Laut typeid("").name() handelt es sich um ein const char [n] .

    cout << &10 << endl;
    

    funktioniert hingegen nicht.

    &10 klappt aus dem Grund nicht, weil 10 ein int ist und ein int ein rvalue ist. Bei &Test muss es sich dann um ein lvalue handeln. &Test kann aber auch ein rvalue sein, weil man einen string doch jederzeit einer anderen stringvaribale zuweisen kann. &Test = "test2" funktioniert aber auch nicht. Warum soll dann &Test ein lvalue sein?

    Dahinter muss doch eine einfache Logik stecken, die besagt wie und was ein rvalue und wie und was ein lvalue ist. Genau das ist das, wonach ich such. Wo gibt es sowas?



  • *seufz*

    Es kommt nicht auf die Typen an. Ob ein Objekt ein R- oder L-value ist, wird allein daraus bestimmt, in was für einem Typ von Ausdruck es gerade in diesem Moment vorkommt und ob da sObjekt ein Literal ist.

    Der Grund weswegen sich integer literale anders verhalten als string literale ist, dass im Standard vorgeschrieben ist, dass man diese string-literale im Ausführbaren Programm vorfinden können muss. Dadurch werden es Objekte, die man referenzieren kann und dadurch qualifizieren sie sich für L-Values. ein integer literal hingegen kann vom Compiler weg optimiert werden wie in:

    int x=1+2;

    Dem Compiler ist es erlaubt daraus:
    int x= 3;

    zu machen. Du kannst also nicht die Addresse von 1 holen, weil die 1 gar nicht im fertigen Programm enthalten ist.

    Merkregel:
    Etwas kann nur dann L-Value sein, wenn es nicht-temporären Speicher belegt
    integer literale belegen keinen Speicher
    string literale belegen Speicher
    Rückgabewerte von Funktionen belegen temporären Speicher.



  • @otze:

    int&& irr = 42;
    int* ptr = &irr;
    

    Und schon hab ich die Adresse von 42, stimmts? 😉



  • 314159265358979 schrieb:

    @otze:

    int&& irr = 42;
    int* ptr = &irr;
    

    Und schon hab ich die Adresse von 42, stimmts? 😉

    Nein. Du hast die Adresse von irr. '42' hat keine Adresse.

    Diese Dinger heißen aus gutem Grund "rvalue" references.



  • Referenzen sind keine Objekte, Schlaumeier. Das war auch keine Frage, sondern vielmehr ein kleier Check, wie viel der liebe Otze wirklich verstanden hat.



  • 314159265358979 schrieb:

    Referenzen sind keine Objekte, Schlaumeier. Das war auch keine Frage, sondern vielmehr ein kleier Check, wie viel der liebe Otze wirklich verstanden hat.

    Gut. 😃



  • Ich finde eigentlich die Regel, dass alle Audrücke auf die man den Referenzoperator anwenden kann L-Values sind, am einfachsten.



  • *Adressoperator



  • inc7 schrieb:

    &10 klappt aus dem Grund nicht, weil 10 ein int ist und ein int ein rvalue ist. Bei &Test muss es sich dann um ein lvalue handeln. &Test kann aber auch ein rvalue sein, weil man einen string doch jederzeit einer anderen stringvaribale zuweisen kann. &Test = "test2" funktioniert aber auch nicht. Warum soll dann &Test ein lvalue sein?

    Dahinter muss doch eine einfache Logik stecken, die besagt wie und was ein rvalue und wie und was ein lvalue ist. Genau das ist das, wonach ich such. Wo gibt es sowas?

    Da ein Stringliteral Speicher belegt, ist es ein L-Value. Das ist so weit korrekt. Jedoch handelt es sich (wie eigentlich weiter oben bereits beschrieben) um ein const char[] und ist damit konstant. Daher kannst du diesem keinen neuen Wert zuweisen.

    Ein L-Value kann immer auch als ein R-Value verwendet werden. Der Zuweisungsoperator (=) braucht immer mindestens ein L-Value (L = R oder L = L jedoch nicht möglich R = R). 🙂

    Gruss



  • anneXus! Ja! Dank dir hab ich es jetzt endlich verstanden! 👍

    Damit die Nachwelt auch was von mir hat, ergänzend zu deinen Beitrag noch ein sehr nützlicher Artikel: http://eli.thegreenplace.net/2011/12/15/understanding-lvalues-and-rvalues-in-c-and-c/. Ich habe sehr lange nach einen guten Artikel suchen müssen, weil die meisten die Antworten im Internet (Foren etc.) viel zu ungenau sind. In dem Artikel wird alles erklärt.

    Meine Faustregeln und eine kurze Zusammenfassung:

    • LV = Hat immer eine Adresse (fest deklariert angegeben)
    • RV = Ist ein Ausdruck, temporär im Speicher (z.B. Werte zusammenkopieren, Beispiel: int result = f1() * f2()).
    • RV kann nicht in LV umgewandelt werden.
    • *-Operator macht aus ein LV ein RV (LValue -> RValue)
    • &-Operator macht aus LV ein RV (LValue -> RValue)
    • Eine LValue muss immer gegeben sein.
    • L = R // möglich
    • R = R // möglich
    • L = L // möglich
    • R = R // nicht möglich

    😉



  • inc7 schrieb:

    # R = R // möglich
    # R = R // nicht möglich

    Sein oder nicht sein 😉



  • Wann ist denn R = R möglich? Kannst du mir dazu ein Beispiel geben, was beweist, dass R = R möglich ist?



  • inc7 schrieb:

    []-Operator macht aus ein LV ein RV (LValue -> RValue)
    [*]&-Operator macht aus LV ein RV (LValue -> RValue)

    Wenn das stimmt, dann hab ich da was ganz Grundlegenes nicht verstanden. Was hat das mit Pointern und Referenzen zu tun? Klar, du canst C/V-qualifier hinzu/weg-casten, aber implizit funktioniert das doch nicht?

    @inc7: Das ist ja grade nicht möglich.

    const int a;//rvalue
    a = 5; //RV = RV ->NICHT MÖGLICH
    


  • Da hast du recht. Es wäre besser gewesen in meinem vorherigen Beitrag zu erwähnen, dass es sich um nicht-const-Typen handelt.


Anmelden zum Antworten