Verständnisproblem: Zeiger auf Zeiger oder doppelte Indirektion



  • Guten Abend liebe C-Programmierer-Kollegen! 🙂

    ich bin gerade dabei, mir Zeiger auf Zeiger anzuschauen, da ich es vermutlich bald einsetzen muss und ich mir das bis jetzt noch nicht angeguckt hatte.
    Bisher hab' ich es nicht gebraucht. Ich habe mit folgendem Beispielprogramm gespielt um zu üben:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main(void) {
        // strtbl[0]..strtbl[n-1]
        char **strtbl = (char *)malloc(10);
    
        int i;
        for(i = 0; i < 10; i++) {
            printf("%i . Peter\n", i);
            // meistens einfach ein *alloc, aber je nach verwendeter Implementierung
            strtbl[i] = strdup("Peter");
        }
        printf("%s\n", *&strtbl[0]); // geht nicht, aber
        printf("%s\n", *&strtbl[3]); // geht problemlos!
        exit(EXIT_SUCCESS);
    }
    

    Ich weiß leider nicht, warum das nicht wie erwartet funktioniert. Ich hätte erwartet, dass ich in strtbl[0] den String "Peter" stehen habe. Das habe ich aber nicht! Erst ab strtbl[3] habe ich "Peter" . Das heißt, es fehlen am Ende 3x"Peter" (0tes Element, 1tes Element und 2tes Element). Was ist da schief gelaufen?

    Vielen Dank schon mal vorab!

    Peter



  • So geht es richtig:

    char **strtbl = malloc(sizeof(char **)*10);

    Die Frage ist, warum...



  • sizeof(char**) ist semantisch falsch, semantisch korrekt wäre sizeof(char*) denn es werden ja einfach Zeiger angelegt (char*) und auf den ersten wollen wir einen Zeiger (char**).

    Was viele vielleicht nicht erwarten - es ist vollkommen gleich, ob sizeof(char*) oder sizeof(char**) oder sizeof(char***) ...

    Zeiger haben immer die selbe Größe, denn ein n-dimensionaler Zeiger ist eben nur ein eindimensionaler Zeiger auf den ersten einer Reihe von (n-1)-dimensionalen Zeigern.

    Man kann also getrost immer sizeof(void*) benutzen, wenn man sich für die Größe eines beliebigen Zeigers interessiert.

    Herzliche Grüße,
    Max


  • Mod

    char**strtbl=malloc(10*sizeof*strtbl);
    

    Alles andere ist ultimativ Unfug.



  • Das ist sicher nicht falsch und wohl auch ganz nützlich um bei eindimensionalen Zeigern dann wirklich die Größe des eigentlichen Typs zu haben, aber deshalb ist der Rest noch lange nicht "ultimativ Unfug".

    Die Hauptsache ist, man versteht was passiert und wie es passiert. Eine präferierte Schreibweise kann man dabei nicht objektiv beurteilen.

    Komm mal runter von dem hohen Roß, camper, und schließ Dich uns kleinen Menschen hier unten an, die wir alle Fehler machen.

    Herzliche Grüße,
    Max



  • Ich würde das so interpretieren:

    irgendeinMirDochEgalWeissNichtGenauTyp bezeichner=malloc(anzahl*sizeof*bezeichner);
    

    Das Zeug rechts ist immer einheitlich! Und die zwei Sternchen nebst spaßiger Syntax machen es zu einem einprägsamen Idiom.


  • Mod

    MaDsTyLe schrieb:

    Die Hauptsache ist, man versteht was passiert und wie es passiert. Eine präferierte Schreibweise kann man dabei nicht objektiv beurteilen.

    Ich nehme das Privileg einer eigenen, subjektiven Meinung für mich in Anspruch.

    MaDsTyLe schrieb:

    Komm mal runter von dem hohen Roß

    zu sattelfest
    Mir ist nicht ganz klar, wo dein erster Beitrag hinführen sollte. Kein Problem, wenn du nach dem ersten Satzt aufgehört hättest. Der Rest ist bloß Konversation.



  • camper schrieb:

    char**strtbl=malloc(10*sizeof*strtbl);
    

    Alles andere ist ultimativ Unfug.

    Das ist definitiv Unfug.

    char**strtbl=calloc(10,sizeof*strtbl);
    

    Das ist was anderes, "definitiv kein Unfug" und sogar besser. Konversation zu betreiben ist in einem Forum üblich, du machst mit deinem ultimativen Geschwafel nichts anderes.



  • camper schrieb:

    zu sattelfest

    Was soll man dazu noch sagen ...
    Ich hab' einen heißen Tipp für Dich - das Ganze nennt sich die "Soziale Kompetenz" (hier mehr dazu).
    Stark sind diejenigen, die Fehler zugeben können - also überlege Dir mal, ob Du Deine arrogante Krampfader nicht mal entfernen möchtest.

    camper schrieb:

    Mir ist nicht ganz klar, wo dein erster Beitrag hinführen sollte. Kein Problem, wenn du nach dem ersten Satzt aufgehört hättest. Der Rest ist bloß Konversation.

    Der Rest ist einfach nur der Hinweis auf die folgende Tatsache:

    Sei Z die (nicht-endliche) Menge aller denkbaren Daten-Zeigertypen, so gilt folgende Aussage:

    ∀ x,y ∈ Z: sizeof x = sizeof y

    Wie Wutz schon geschrieben hat, halte auch ich derartige Konversation für sinnvoll und freue mich selbst darüber, wenn ich in den Genuß komme.
    So hab dank Wutz, calloc() war mir noch nicht bekannt. 🙂

    Herzliche Grüße, Max



  • MaDsTyLe schrieb:

    Sei Z die (nicht-endliche) Menge aller denkbaren Zeigertypen, so gilt folgende Aussage:
    ∀ x,y ∈ Z: sizeof x = sizeof y

    Sind Funktionszeiger zwangsläufig genausolang wie Datenzeiger?



  • Haha, danke volkard!

    Ich editiere mal eben 🙂

    EDIT:
    Naja, mal drauflos spekuliert ist ein Funktionszeiger ja ein Datenzeiger, denn zur Runtime liegt der Instruktionscode einer beliebigen Funktion ebenfalls im Speicher. Funktionszeiger werden nur anders interpretiert, nämlich um den PC (program counter) neu zu setzen - sprich zu springen. Also enthalten Funktions- und Datenzeiger Speicheradressen. Damit die bei Funktionszeigern reinpassen, müssen diese also mindestens so groß wie Datenzeiger sein.

    Ok, hiermit ist Dein Einwand nun bestätigt - dank OOP 🙂

    Herzliche Grüße,
    Max



  • MaDsTyLe schrieb:

    Haha, danke volkard!

    Gern geschehen.

    MaDsTyLe schrieb:

    Ok, hiermit ist Dein Einwand nun bestätigt - dank OOP 🙂

    Nein, das betrifft Methodenzeiger von C++. Die müssen länger sein, weil in so einem "Zeiger" vielleicht eine statische Methode (einfache Adresse), vielleicht eine virtuelle Methode (einfach ein Offset auf die vtbl), oder gar eine (virtuelle) Methode auf eine (virtuelle) Basisklasse (Basisklassen(zeiger)offset, hammer-kompliziert, eine der Schattenseiten von C++...

    Ich meine nur C mit den Speichermodellen tiny compact medium large huge und so. Das kann man natürlich auch für größere Prozessoren aufziehen. Auch, wenn es derzeit totaler Quatsch ist. Ich kenne jetzt den C-Standard dahingehend nicht. Ich vermute, daß sie sich offen halten, sowas wieder einzuführen, und deshalb Datenzeiger und Funktionzeiger unterschiedlich behandeln.



  • volkard schrieb:

    Nein, das betrifft Methodenzeiger von C++.

    Das meinte ich doch mit OOP - ohne OOP wird man doch wohl kaum Methoden- sondern nur einfache Funktionszeiger bauen können oder sehe ich das falsch?

    Herzliche Grüße,
    Max


  • Mod

    MaDsTyLe schrieb:

    camper schrieb:

    zu sattelfest

    Was soll man dazu noch sagen ...
    Ich hab' einen heißen Tipp für Dich - das Ganze nennt sich die "Soziale Kompetenz" (hier mehr dazu).
    Stark sind diejenigen, die Fehler zugeben können - also überlege Dir mal, ob Du Deine arrogante Krampfader nicht mal entfernen möchtest.

    Diese Forum ist nicht zum Streiten da. Also bitte sachlich bleiben.
    Edit: Oder wenn schon Streit, dann bitte auf höherem Niveau; so macht es einfach keine Spass.



  • MaDsTyLe schrieb:

    volkard schrieb:

    Nein, das betrifft Methodenzeiger von C++.

    Das meinte ich doch mit OOP - ohne OOP wird man doch wohl kaum Methoden- sondern nur einfache Funktionszeiger bauen können oder sehe ich das falsch?

    Herzliche Grüße,
    Max

    Klar. Aber einfache Funktionszeiger könnten anders lang sein als Datenzeiger. Verfolge meinen Hinweis auf die Speichermodelle mal kurz. Ok, es ist eine Sitte von vor 20 Jahren. Ich gebe es zu. Wegendessen dachte ich daran, daß die Gleichheit der Längen vermutlich nicht im Standard definiert ist.



  • Ok, got it.

    Sag mal bist Du (wobei ich dann eigentlich mehr zum "Sie" neige) Volkard Henkel, der Autor von Volkards C++-Kurs?

    Herzliche Grüße,
    Max



  • Jup, das bin ich. Das "Du" bleibt angemessen.



  • Wahnsinn ... damit habe ich meine ersten Schritte gemacht 🙂
    Herzlichen Dank dafür!

    Wieso schreibst Du (das "Du" beizubehalten ist jetzt echt schwer ...) nicht mal ein Buch? Das würde doch sicher Anklang finden.



  • MaDsTyLe schrieb:

    Wieso schreibst Du nicht mal ein Buch? Das würde doch sicher Anklang finden.

    Bis ich ein Buch guten Gewissens in die Welt gehen lassen würde, müßte ich ein Jahr Arbeitszeit hineinstecken. Das bekäme ich nicht wieder raus. Vielleicht, wenn ich ähnlich gut wie Meyers wäre, aber das bin ich bei Weitem nicht. Schnellen Müll rauspusten will ich nicht. Dazwischen sehe ich viele Autoren, die (wohl auch aus Berufung) genau ein Buch schreiben und keins mehr.



  • MaDsTyLe schrieb:

    Der Rest ist einfach nur der Hinweis auf die folgende Tatsache:

    Sei Z die (nicht-endliche) Menge aller denkbaren Daten-Zeigertypen, so gilt folgende Aussage:

    ∀ x,y ∈ Z: sizeof x = sizeof y

    Bist Du dir da sicher? Ich meine, es gibt oder gab mal Maschinen mit 36-Bit-Worten, in deren C-Implementierungen Zeiger auf char und Zeiger auf int unterschiedlich groß waren. Leider finde ich gerade keine harten Daten. Kann also gut sein, dass ich falsch liege. Falls ich noch etwas finde, werde ich es hier nachtragen.


Log in to reply