char Array Verständnisproblem



  • Hallo.

    ich habe hier ein Problem mit char-Arrays. Liegt vermutlich daran, dass ich es nicht verstehe, wie diese funktionieren.

    Ich möchte diese Funktion verwenden: int execv(const char *path, char *const argv[])

    Mein Problem liegt darin, das ich den Datentyp char* const argv[] nicht erstellt bekomme. Meine Frage ist also vorweg, was ist das überhaupt und wo ist der Unterschied zu const char *path ?

    Aufbau von const char*

    std::string foo = "Hello";
    const char* bar = foo.c_str();
    

    bar ist intern dann folgendermaßen aufgebaut.

    bar[0] = 'H';
    bar[1] = 'e';
    bar[2] = 'l';
    bar[3] = 'l';
    bar[4] = 'o';
    bar[5] = '\n;
    

    Soweit habe ich das kapiert. Was mich etwas verwirrt ist, wo ist da der Pointer? char* ist ja ein Pointer auf char. Somit wäre const char* ein Konstanter Pointer auf char , Was bedeutet das die Speicheradresse nicht verändert werden kann.
    char* const argv[] wäre ein char Pointer auf ein Konstantes char Array. Aber bar aus dem obigen Beispiel ist ja auch ein Array. Also ist char* immer ein Array?

    Ihr seht ich raffe es nicht.

    Das folgende Problem, was auch eine Compilermeldung wirft, kann ich leider nicht lösen, weil mir einfach das obige Wissen fehlt.

    std::string param = "--version";
    char *argv = new char[param.size() + 1];
    argv[param.size()] = '\0';
    strcpy(argv, param.c_str());
    
    int status = execv("ls", argv);
    

    cannot convert 'char* const' to 'char* const*' for argument '2' to 'int execv(const char*, char* const*)'

    Von const char* und Konsorten scheint es irgendwie undendlich viele Varianten zu geben und ich habe hier gänzlich den Überblick verloren.

    Über einige Tipps wäre ich dankbar.

    Grüße.



  • create_problem schrieb:

    char* const argv[] wäre ein char Pointer auf ein Konstantes char Array.

    Nee, das ist ein Array von konstanten Pointern, die auf char zeigen. Etwa so:

    char * const bla[] = {"Eins", "Zwei", "Drei"};



  • Belli schrieb:

    Etwa so:

    char * const bla[] = {"Eins", "Zwei", "Drei"};

    In diesem Fall (für execv) muss es am Ende ein NULL-Pointer sein:

    char * const bla[] = {"Eins", "Zwei", "Drei", NULL};
    

    @create_problem

    Du kannst auch mal bei www.cdecl.org deine Definition eingeben und dir das ins englische übersetzen lassen.



  • create_problem schrieb:

    Mein Problem liegt darin, das ich den Datentyp char* const argv[] nicht erstellt bekomme. Meine Frage ist also vorweg, was ist das überhaupt und wo ist der Unterschied zu const char *path ?

    Wurde ja schon erklärt, wo der Unterschied zwischen
    char*const* und
    const char* liegt.

    create_problem schrieb:

    Aufbau von const char*

    std::string foo = "Hello";
    const char* bar = foo.c_str();
    

    bar ist intern dann folgendermaßen aufgebaut.

    bar[0] = 'H';
    bar[1] = 'e';
    bar[2] = 'l';
    bar[3] = 'l';
    bar[4] = 'o';
    bar[5] = '\n;
    

    bar ist ein Zeiger, der "intern" eine Adresse speichert -- und zwar die Adresse des ersten Zeichens, was irgendwo im Speicher steht. In diesem Fall ist es ein Speicherbereich, um den sich das string-Objekt foo kümmert (und irgendwann von foo wieder freigegeben wird). Für die Ende-Markierung kommt auch kein '\n' sondern ein '\0' zum Einsatz, der Nullterminator.

    create_problem schrieb:

    Soweit habe ich das kapiert. Was mich etwas verwirrt ist, wo ist da der Pointer? char* ist ja ein Pointer auf char. Somit wäre const char* ein Konstanter Pointer auf char , Was bedeutet das die Speicheradresse nicht verändert werden kann.

    Nein. Das const an der Stelle bezieht sich auf das, worauf der Zeiger zeigt. Wenn du eine Variable des Typs const char* anlegst, ist das eine Zeigervariable, deren Adresse du verändern kannst. Du kannst diese Zeigervariable nur nicht ohne weiteres dazu verwenden, das zu verändern, wodrauf der Zeiger zeigt.

    create_problem schrieb:

    char* const argv[] wäre ein char Pointer auf ein Konstantes char Array. Aber bar aus dem obigen Beispiel ist ja auch ein Array. Also ist char* immer ein Array?

    Nö. Die Deklaration sagt "argv ist ein Array (unbekannter Größe) von unveränderlichen Zeigern auf veränderliche Zeichen." Allerdings kann man Arrays gar nicht an Funktionen übergeben oder zurück geben, wie man es beispielsweise bei int-Werten machen würde. Schreibst du das als Funktionsparameter auf, geht der Compiler hin und macht daraus in Wirklichkeit char*const*argv . argv ist also nur ein Zeiger.

    create_problem schrieb:

    Ihr seht ich raffe es nicht.

    Die Deklarationssyntax ist halt einfach Sch.....
    Das wird schon. 😉

    create_problem schrieb:

    Das folgende Problem, was auch eine Compilermeldung wirft, kann ich leider nicht lösen, weil mir einfach das obige Wissen fehlt.

    std::string param = "--version";
    char *argv = new char[param.size() + 1];
    argv[param.size()] = '\0';
    strcpy(argv, param.c_str());
    int status = execv("ls", argv);
    

    cannot convert 'char* const' to 'char* const*' for argument '2' to 'int execv(const char*, char* const*)'

    Wo er Recht hat, hat er Recht. Die Typen passen nicht zueinander. Das eine ist ein Zeiger auf char, das andere ein Zeiger auf Zeiger auf char. Was ich komisch finde ist, dass die Funktion die Zeichenketten ändern konnen will; denn sonst wäre da noch ein const mehr dabei. Aber in der Dokumentation zu execv finde ich keine Info, dass die Zeichenketten wirklich verändert werden. Da hat also jemand leider ein "const" vergessen. Probier es mal so:

    std::string param = "--version";
    char*const args[] = {
        const_cast<char*>(param.c_str()),
        0 }; // Auch dieses Array muss nullterminiert sein, sagt die Doku!
    int status = execv("ls", args);
    

    Und wenn execv doch irgendwie die Zeichenketten ändern will, dann dürfen wir hier kein const_cast verwenden. Dann müsste man die Zeichen in einen temporären Puffer umkopieren, z.B. in einen Vector.



  • Hallo.

    Danke für Eure ausführlich Erklärung. Ich glaube, das ich es jetzt kapiert habe, aber das werde ich schnell genug rausfinden :-).

    Eine kleine Frage hätte ich noch zur Null-Terminierung. Ist das egal ob ich '\0' oder 0 oder NULL schreibe, oder gibt es da auch besondere Unterschiede?

    Grüße.

    PS: Der Link: http://www.cdecl.org ist wirklich super.


  • Mod

    '\0' ist ein char mit Wert 0, 0 ist ein int mit Wert 0, NULL ist irgendein C-Makro, welches wer weiß wie definiert ist und eher für Nullzeiger verwendet werden sollte (aber nur in C, in C++ nimm dafür lieber 0 oder noch besser den neuen null_ptr). Der Unterschied zwischen char und int kann zum Beispiel von Bedeutung sein, wenn es um das Auflösen von Templateparametern geht. Ansonsten sind Integerwerte (auch char ist eine Art Integer) implizit ineinander konvertierbar.


Anmelden zum Antworten