const char *var oder string ???



  • Ah ok.
    Also nur zum Verständis:

    Ich habe irgendwo Text, sei es in einem string, einem c-string oder char array.
    dem char pointer übergebe ich die adresse, und der zeigt auf den Anfang dessen.
    Ist das so richtig?

    der char pointer kann also mit jeder oben genannten Variablen bestückt werden,
    da ja alle irgendwie mit char zu tun haben.
    Kann man das so stehen lassen?



  • @robert123 sagte in const char *var oder string ???:

    Ich habe irgendwo Text, sei es in einem string, einem c-string oder char array.
    dem char pointer übergebe ich die adresse, und der zeigt auf den Anfang dessen.
    Ist das so richtig?

    char ch = 'A';
    char *foo = "foo";
    char bar[] = "bar";
    std::string qux = "qux";
    
    char *p = &ch;  // p Zeigt auf ch
    p = foo; // oder auch p = foo; ... p zeigt auf das 'f' auf das auch foo zeigt.
    p = bar; // oder auch p = &bar[0]; ... p zeigt auf das 'b' das im ersten Element des Arrays bar steht.
    p = &qux[0]; // p zeigt auf das 'q' des strings "qux" der sonstwo im Speicher steht.
    
    char const *pstr = qux.c_str();  // c_str() gibt einen Pointer auf char const zurück.
    // pstr zeigt auf das 'q' das irgendwo im Speicher steht.


  • Ich möchte als Kandidat noch std::string_view in den Raum werfen.



  • Vielleicht noch wichtig: du kannst dem char* nicht ansehen, ob das ein Zeiger auf ein einzelnes Zeichen oder einen C-String ist. Technisch ist es ja immer ein Zeiger auf ein Zeichen. Du musst es also selbst wissen, ob du den char* als Zeiger auf einen C-String ansehen willst. Die cout-Ausgabe weiß das auch nicht, d.h. std::cout nimmt immer an, dass ein char-Pointer auf einen nullterminierten String zeigt.

    Falsch:

    #include <iostream>
    int main() {
      char c = 'X';
      char *pc = &c; 
      std::cout << pc; // FALSCH!
    }
    

    Der Zeiger muss auch nicht auf das erste Zeichen eines C-Strings zeigen:

    #include <iostream>
    int main() {
      char arr[] = "0123456789\n";
      char *pc = &arr[5]; 
      std::cout << pc; // ok, aber nicht Anfang
    }
    


  • Ich danke euch sehr für die Ausführungen aber jetzt bin ich verwirrt.
    @Swordfish

    In deinem code steht zum einen:

    char *foo = "foo";
    

    und zum anderen

    char *p = &ch;
    

    Eine Zeigervariable speichert doch nur Adressen, wie kann es sein, dass man ihn mit einer zeichenkette Initialisieren kann?
    Wenn ich das richtig verstanden habe, dann zeigt dieser Zeiger auf das "f" von "foo" richtig?
    aber wieso kann ich ihn mit einer Zeichenkette initialisieren? Alles was ich bisher über Zeiger gelesen habe, hatte immer etwas mit dem Adressoperator zu tun.

    @wob
    Ich habe gerade den oberen code von dir ausprobiert und es kommt nicht das gewünschte Ergebnis raus,
    also keine Adresse. Angezeigt wird mir zwar das "X", aber gefolgt von irgendwelchen Zeichen.
    Ok, das scheint wie du sagst Falsch zu sein, aber wie kann ich denn über einen char pointer die Adresse erfragen?
    Mit einem integer pointer und einer int Variable funktioniert es ja eben genau so.

    Danke euch nochmal vielmals.
    Ihr habt sicher besseres zu tun, als solche Basics zu besprechen.
    🙏🏻



  • @robert123 sagte in const char *var oder string ???:

    Eine Zeigervariable speichert doch nur Adressen, wie kann es sein, dass man ihn mit einer zeichenkette Initialisieren kann?

    Weil der Typ eines String literal Array of N const char ist:

    https://en.cppreference.com/w/cpp/language/string_literal:

    1. Narrow multibyte string literal. The type of an unprefixed string literal is const char[N], where N is the size of the string in code units of the execution narrow encoding, including the null terminator.

    Standart: 5.13.5 String literals [lex.string]



  • Ok, und ein array selbst auf das erste Element von sich selbst zeigt, richtig.
    War das richtig ausgedrückt?



  • @robert123 sagte in const char *var oder string ???:

    wie kann ich denn über einen char pointer die Adresse erfragen?

    Es gibt eine Überladung des operator<<() für ostreams und char const*1). Diese Überladung gibt nicht die Adresse aus sondern interpretiert den Pointer als den Beginn einer nullterminierten Zeichenkette. Um die Adresse auszugeben kannst Du nach void* casten:

    #include <iostream>
    
    int main()
    {
        char const *foo = "foo";
        std::cout << '"' << foo << "\"\n" << "Address: " << static_cast<void const*>(foo) << '\n';
    }
    
    1. https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2 :
    1. Behaves as an FormattedOutputFunction. After constructing and checking the sentry object, inserts successive characters from the character array whose first element is pointed to by s.
      For the first and third overloads (where CharT matches the type of ch), exactly traits::length(s) characters are inserted.
      For the second overload, exactly std::char_traits<char>::length(s) characters are inserted.
      For the last two overloads, exactly traits::length(reinterpret_cast<const char*>(s)) are inserted.
      Before insertion, first, all characters are widened using os.widen(), then padding is determined as follows: if the number of characters to insert is less than os.width(), then enough copies of os.fill() are added to the character sequence to make its length equal os.width(). If (out.flags()&std::ios_base::adjustfield) == std::ios_base::left, the fill characters are added at the end of the output sequence, otherwise they are added before the output sequence. After insertion, width(0) is called to cancel the effects of std::setw, if any.
      The behavior is undefined if s is a null pointer.


  • Oh man.
    Das habe ich so noch nie gehört "...nach void* casten. 🙃
    Es liegt noch einiges an Arbeit vor mir.
    Danke dir



  • @robert123 sagte in const char *var oder string ???:

    Ich habe gerade den oberen code von dir ausprobiert und es kommt nicht das gewünschte Ergebnis raus,
    also keine Adresse.

    Habe ich ja versucht zu beschreiben. Man möchte mit cout C-Strings ausgeben können. Daher wird char* von cout (bzw. dem operator<<) spezialbehandelt, nämlich so, als würde es auf einen auszugebenden C-String zeigen - und vom cout ist eben nicht unterscheidbar, ob das stattdessen ein normaler Pointer auf ein genau ein char (und keinen String) sein soll. Der Code gibt also das X und dann das aus, was danach im Speicher steht. Dorthin darf aber nicht zugegriffen werden. Daher ist das Verhalten des Programms undefiniert. Wenn du mit dem Address Sanitizer kompilierst (Parameter -fsanitize=address bei g++/clang), siehst du, dass das Programm damit einen stack-buffer-overflow erzeugt.



  • Danke dir.
    Das muss ich mir merken. Das habe ich bisher in keinem Buch gefunden.


Anmelden zum Antworten