Array vs. Pointer vs. Char - Problem



  • Ein freundliches Hallo! 🙂

    ich habe vor 1-2 Wochen begonnen C++ zu programmieren. nun eine Frage zum obigen Titel die mich sehr verwirrt:

    deklariere ich mir ein int-array und gebe es aus

    int a[]={1,2,3,4};
    cout << a;
    

    , so erhalte ich erwartungsgemäß (nachdem was ich gelernt habe, dass der Name des Arrays dessen Anfangsadresse widerspiegelt) folgendes:

    0014FDD8
    

    . irgendein beliebiger Ort im Arbeitsspeicher.

    so nun das Gleiche aber mit einem char-array, macht es etwas anderes:

    char s[]="Hallo";
    cout << s
    

    Ergebnis:

    Hallo
    

    .
    (selbst mit

    char s[]={'H','a','l','l','o','\0'}
    cout << s
    

    als super korrekte array defintion wird nur "Hallo" ausgegeben).

    warum verhält sich Char anders? warum gibt es mir nicht auch die Anfangsadresse des arrays aus..? wo ist meine Wissenslücke? das habe ich auch nach vielen Tutorials im web nicht verstanden.. 😞

    (hat es was mit Pointer zu tun? ich habe hier und da gesehen, dass man strings auf 2 Wege definiert - mit einem char-array oder mit char *. ich kann eigtl mit Pointern schon umgehen und programmieren, nur im speziellen Zusammenhang mit Char komme ich irgendwie nicht klar.)

    Mit freundlichen Grüßen,
    Hectorius



  • Es gibt verschiedene Überladungen für operator<< :

    Da gibt es einmal operator<<(void*)

    und es gibt einmal operator<<(ostream& os, const char*)

    Für das int-Array ist erstere die besser passende Überladung. void hat keine Typinformation, es gibt dann einfach die Adresse aus.

    Logischerweise ist zweiteres die Wahl für ein char-Array. Diese Überladung bit solange Zeichen aus, bis sie auf das Terminierungszeichen '\0' stößt.



  • Hi,
    das liegt an der Funktionsweise der Ausgabe von cout . Ich nehme mal an, dass du nach den 2 Wochen C++ noch nicht weißt, wie cout eigentlich funktioniert. Um zu entscheiden wie und was cout nun ausgibt, kommen verschiede Dinge wie Operatorenüberladung und Funktionsüberladung zum Einsatz. Wenn dir das noch nichts sagt, ein Beispiel für Funktionsüberladung (und die implizite Konvertierung von Arrays zu Zeigern):

    void foo(char const* s)
    {
        std::cout << "char const*\n";
    }
    
    void foo(void* p)
    {
        std::cout << "void*\n";
    }
    
    int main()
    {
        char string[] = "Hallo"; // dies ist ein char Array
        int array[] = {1,2,3}; // dies ist ein int Array
        foo(string); // das char Array wird implizit in einen char const* konvertiert
        foo(array); // das int Array wird implizit in den void* konvertiert
    }
    

    Ausgabe schrieb:

    char const*
    void*

    Hier gibt es zwei Funktionen mit dem selben Namen: foo .

    Nun kann man auch Operatoren (wie den << Shiftoperator) überladen! In sehr einfachter Form:

    using namespace std;
    
    struct data_t
    {
        int i;
        char const* s;
    };
    
    // Hier wird der Operator << global überladen, sodass er auf der linken Seite einen ostream und auf der rechten Seite ein data_t annimmt
    ostream& operator<<(ostream& os, data_t const& d)
    {
        os << d.i << "\n" << d.s;
        return os;
    }
    
    int main()
    {
        data_t d = {5, "hallo"};
        cout << d << endl; // cout ist eine Instanz von std::ostream
    }
    

    Ausgabe schrieb:

    5
    hallo

    out schrieb:

    Es gibt verschiedene Überladungen für operator<<:

    Da gibt es einmal operator<<(void*)

    und es gibt einmal operator<<(ostream& os, const char*)

    Für das int-Array ist erstere die besser passende Überladung. void hat keine Typinformation, es gibt dann einfach die Adresse aus.

    Logischerweise ist zweiteres die Wahl für ein char-Array. Diese Überladung bit solange Zeichen aus, bis sie auf das Terminierungszeichen '\0' stößt.

    Genau so sieht es aus. Wie in meinem ersten Beispiel wird nämlich dein char Array implizit zu einem char const* konvertiert und dann der operator<<(ostream& os, const char*) aufgerufen. Bei dem int Array wird es implizit in einen void* konvertiert und dann der operator<<(void*) vom cout aufgerufen. Mach dir also noch keinen Kopf drum, wenn du die Magie hinter cout noch nicht versteht 😃



  • wow.. vielen Dank!

    ich bin Physiker und habe bisher nur mit Matlab programmiert. da muss man sich um solch tiefergreifenden Dinge keine Gedanken machen.

    Biolunar schrieb:

    Ich nehme mal an, dass du nach den 2 Wochen C++ noch nicht weißt, wie cout eigentlich funktioniert.

    ja, das trifft es wohl.. das es an cout liegt, darauf wäre ich jetzt nie gekommen.. bin schon fast verrückt geworden.

    deine Erklärung lässt mich fast fragen, ob ich gleich wieder aufhören sollte mit C++, da diese neuen Dinge im Moment ziemlich erdrückend wirken.. 😕 ^^
    bevor ich weitere vermeintlich dumme Fragen stelle, werde ich erstmal viel googlen und mich dazu einlesen.

    vllt nur eine Sache: würde printf auch das Problem lösen?



  • Hectorius schrieb:

    vllt nur eine Sache: würde printf auch das Problem lösen?

    Das "Problem" lässt sich lösen, indem du den char-Pointer in einen void-Pointer umwandelst:

    char s[] = "blabla";
    cout << static_cast<void*>(s);
    

    Dann wir die void*-Überladung aufgerufen und somit die Adresse ausgegeben.

    Mit printf existiert das Problem nicht (dafür andere), da es hier natürlich keine überladenen Versionen gibt und die zu verwendende Ausgabemethode durch ein Formatkennzeichen angegeben wird. %s gibt immer als String aus (auch wenn es kein char-Zeiger ist, dann kommt halt Müll raus), %p immer als Adresse.



  • Hectorius schrieb:

    C++ noch nicht weißt, wie cout eigentlich funktioniert.

    ja, das trifft es wohl.. das es an cout liegt, darauf wäre ich jetzt nie gekommen.. bin schon fast verrückt geworden.

    deine Erklärung lässt mich fast fragen, ob ich gleich wieder aufhören sollte mit C++, da es im Moment ziemlich erdrückend wirkt.. 😕 ^^[/quote]
    Gewöhn dich dran.
    Aber wenn du alles kannst ist es verdammt cool.

    vllt nur eine Sache: würde printf auch das Problem lösen?

    Ja, printf("%p") würde dir die Adresse geben.
    Aber printf sollte man in C++ nicht benutzen, nimm lieber cout.
    Wenn du die Adresse eines char Arrays haben willst, caste:

    std::cout << static_cast<void*>(s);
    

    Übrigens:

    (selbst mit

    char s[]={'H','a','l','l','o','\0'}
    cout << s
    

    als super korrekte array defintion wird nur "Hallo" ausgegeben).

    Dir ist hoffentlich klar, dass das keinen Unterschied machen sollte, schließlich sind beide Formen absoult äquivalent?

    Im Übrigens ist std::string char[] oder const char* oft vorzuziehen, da es einfacher zu Nutzen ist als const char* Pointer.



  • Nathan schrieb:

    Aber wenn du alles kannst ist es verdammt cool.

    hm, motivation accepted! 🕶

    ich muss mir die gesagten Dinge in Ruhe durch den Kopf gehen lassen.
    vielen Dank an alle!



  • Hectorius schrieb:

    Nathan schrieb:

    Aber wenn du alles kannst ist es verdammt cool.

    hm, motivation accepted! 🕶

    ich muss mir die gesagten Dinge in Ruhr durch den Kopf gehen lassen.
    vielen Dank an alle!

    Aber ohne Buch brauchst du auch gar net erst anfangen^^


Log in to reply