getline()



  • Hallo! Ich habe folgendes Listing:

    /* getline.c */
    #define _GNU_SOURCE
    #include <stdio.h>
    #include <stdlib.h>
    #include <stddef.h>
    
    int main(void) {
       FILE *fd;
       /* Bitte die Datei und event. den Pfad anpassen */
       char *datei = "/home/user/testdatei.txt";
       int nRet;
       size_t *t = malloc(0);
    
       char **gptr = malloc(sizeof(char*));
       *gptr = NULL;
    
       if ( (fd = fopen(datei,"r")) == NULL) {
          fprintf(stderr, "\nKonnte Datei %s nicht öffnen!", datei);
          return EXIT_FAILURE;
       }
       while( (nRet=getline(gptr, t, fd)) > 0)
          fputs(*gptr,stdout);
      return EXIT_SUCCESS;
    }
    

    Sinn ist es, getline einen Puffer mit Null zu übergeben und die Größe des Puffers soll 0 sein, damit getline den Speicher selber verwaltet.

    Ich verstehe nicht, warum im Buch die Lösung so aussieht:

    char **gptr = malloc(sizeof(char*));

    Wäre nicht auch folgendes gegangen:

    char *gptr = (char *)malloc(sizeof(char));

    Wo liegen denn die Unterschiede?

    Thx


  • Mod

    Das aus dem Buch hält sich an die vordefinierte Schnittstelle von getline, das andere nicht. Ich würde das Buch trotzdem nicht zum Vorbild nehmen, wie da mit Zeigern hantiert wird ist Schrott.



  • Deine Version würde auch passen - ich denke der Autor hatte ordentlich die Hände am Sack. Sieht aus, als ob er selber noch C lernt und sich da verzettelt.

    Wenn die Version von getline( ) meiner entspricht, ist insebsonders der Umgang mit dem t ein (völlig unnötiger) Fehler.



  • Ich meine char** pointer ist doch das gleiche wie char* pointer[], oder? Wenn ich dann also char **gptr = malloc(sizeof(char*)) schreibe, dann erstellt er ein Array mit char-arrays, dieses Array hat aber keine feste anzahl an Elementen, aber auf jeden Fall eine feste Größe von 1 Byte?


  • Mod

    PS: Die "richtige" Lösung sähe übrigens so aus:

    char *gptr = NULL;
    size_t t = 0;
    // ...
    getline(&gpts, &t, fd)
    

  • Mod

    CCat schrieb:

    Ich meine char** pointer ist doch das gleiche wie char* pointer[], oder?

    char* pointer[] ist keine gültige Syntax.

    Wenn ich dann also char **gptr = malloc(sizeof(char*)) schreibe, dann erstellt er ein Array mit char-arrays,

    Da sind nirgendwo Arrays. Arrays sind keine Zeiger, Zeiger sind keine Arrays.

    dieses Array hat aber keine feste anzahl an Elementen, aber auf jeden Fall eine feste Größe von 1 Byte?

    Da ist ein Zeiger, der heißt gptr, der zeigt (vom Typen her) auf einen char* und zeigt (vom Wert her) auf ein Stück Speicher, welches einen char* aufnehmen könnte.

    PPS: Ich habe den Verdacht, dass deine Verwirrung vermutlich einem extrem schlechten Lehrer geschuldet ist. Noch einmal zur Wiederholung: Der Code aus dem Buch ist Schrott! Absoluter Mega-Schrott, den jeder Anfänger nach zwei Wochen besser kann. Er bedient technisch gesehen die Schnittstelle von getline korrekt, aber
    1. Der Code verfehlt völlig den Zweck
    2. Der Code ist anderswo absolut falsch, insbesondere Zeiger scheint der Autor überhaupt nicht zu können.
    Folgerung: Lerne nicht weiter mit diesem Buch! Ernsthaft. Das ist eines der schlechtesten Stücke C, die ich je gesehen habe. Wie soll man damit lernen? Da lernst du nur wie es nicht geht. Wie soll ein Autor, der nicht C kann, anderen C beibringen?



  • Noch die Version, wie sie Dir vielleicht vorschwebte:

    size_t t=1;
       char *gptr=malloc(1);
    
       getline(&gptr, &t, fd);
    
       free(gptr);
    

    (Oder malloc(0) mit t=0 - aber das wäre unnötig weit weg von Standard C.)



  • Danke für die Ant 👍 worten.

    Ich bringe mir das alles selber bei. 😃 Ich bein eigentlich angehender Java-Programmierer, aber da kommt man ja mit Pointer und Malloc gar nicht in Berührung. 😕

    Aber warum ist char** denn nicht das gleiche wie char* pointer[]? Ich meine bei argv für die Kommandozeilenparameter kann man doch auch zwischen char** argv und char* argv[] wählen, oder? Und daher dachte ich, das wäre das gleiche.


  • Mod

    Furble Wurble schrieb:

    Noch die Version, wie sie Dir vielleicht vorschwebte:

    size_t t=1;
       char *gptr=malloc(1);
    
       getline(&gptr, &t, fd);
    
       free(gptr);
    

    (Oder malloc(0) mit t=0 - aber das wäre unnötig weit weg von Standard C.)

    Das wird explodieren. Oder zumindest sollte es das. Wenn das durchläuft, ist das purer Zufall.


  • Mod

    CCat schrieb:

    Aber warum ist char** denn nicht das gleiche wie char* pointer[]?

    Weil es immer noch keine char* pointer[] gibt. Probier's aus:
    https://ideone.com/ADu1hy

    Ich meine bei argv für die Kommandozeilenparameter kann man doch auch zwischen char** argv und char* argv[] wählen, oder? Und daher dachte ich, das wäre das gleiche.

    Für Funktionsargumente gelten andere Regeln. char *argv[] ist dort tatsächlich gleichbedeutend mit char** . Das ist aber keine tiefschürfende Äquivalenz von Pointern und Arrays, sondern einfach nur eine andere Schreibweise für Pointer als Funktionsparameter.

    Arrays sind keine Pointer! Pointer sind keine Arrays! Ganz selten mag man mit viel Glück damit wegkommen, wenn man Pointer für Arrays hält, aber allerspätestens bei Pointern auf Pointern oder Arrays von Arrays bricht diese Annahme vollkommen zusammen.



  • SeppJ schrieb:

    Furble Wurble schrieb:

    Noch die Version, wie sie Dir vielleicht vorschwebte:

    size_t t=1;
       char *gptr=malloc(1);
    
       getline(&gptr, &t, fd);
    
       free(gptr);
    

    (Oder malloc(0) mit t=0 - aber das wäre unnötig weit weg von Standard C.)

    Das wird explodieren. Oder zumindest sollte es das. Wenn das durchläuft, ist das purer Zufall.

    Was genau meinst Du?



  • SeppJ schrieb:

    CCat schrieb:

    Aber warum ist char** denn nicht das gleiche wie char* pointer[]?

    Weil es immer noch keine char* pointer[] gibt. Probier's aus:
    https://ideone.com/ADu1hy

    So muss das, Seppel: https://ideone.com/40S3Xl
    🙂


  • Mod

    SeppenDepp schrieb:

    SeppJ schrieb:

    CCat schrieb:

    Aber warum ist char** denn nicht das gleiche wie char* pointer[]?

    Weil es immer noch keine char* pointer[] gibt. Probier's aus:
    https://ideone.com/ADu1hy

    So muss das, Seppel: https://ideone.com/40S3Xl
    🙂

    Ok, so geht's natürlich auch. Dann ist's aber auch kein char**.



  • OK, vielen Dank. Ich habe da glaube ich jede Menge durcheinander geworfen. Ich versuche das jetzt mal zu erklären, ob ich es verstanden habe:

    Also, bspw. char** matrix ist einfach eine Variable, die Char-Pointer aufnehmen kann.

    Soweit so gut. Nur warum kann ich getlin() jetzt ein *char übergeben, obwohl die Methode ein **char verlangt? 😕



  • SeppJ schrieb:

    SeppenDepp schrieb:

    SeppJ schrieb:

    CCat schrieb:

    Aber warum ist char** denn nicht das gleiche wie char* pointer[]?

    Weil es immer noch keine char* pointer[] gibt. Probier's aus:
    https://ideone.com/ADu1hy

    So muss das, Seppel: https://ideone.com/40S3Xl
    🙂

    Ok, so geht's natürlich auch. Dann ist's aber auch kein char**.

    Doch ...
    https://ideone.com/wfcx2I

    Vergiss es, Alter. C ist nicht so dein Ding.



  • CCat schrieb:

    Also, bspw. char** matrix ist einfach eine Variable, die Char-Pointer aufnehmen kann.

    Nicht ganz. Das ist ne Variable die Adressen von char* aufnehmen kann.

    CCat schrieb:

    Wenn ich also matrix = malloc(10 * sizeof(char *)); ausführe, dann habe ich platz für 10 char-pointers?

    Kann sein. Aber besser ist:
    char *p[10]; // 10 char*
    char **matrix = p;

    ^^ klappt immer.


  • Mod

    SeppenDepp schrieb:

    SeppJ schrieb:

    SeppenDepp schrieb:

    SeppJ schrieb:

    CCat schrieb:

    Aber warum ist char** denn nicht das gleiche wie char* pointer[]?

    Weil es immer noch keine char* pointer[] gibt. Probier's aus:
    https://ideone.com/ADu1hy

    So muss das, Seppel: https://ideone.com/40S3Xl
    🙂

    Ok, so geht's natürlich auch. Dann ist's aber auch kein char**.

    Doch ...
    https://ideone.com/wfcx2I

    Vergiss es, Alter. C ist nicht so dein Ding.

    Not sure if joking or just stupid.

    Das eine ist ein Array von Zeigern, das andere ist ein Zeiger auf einen Zeiger. Da ich eher auf stupid als auf joking tippe, hier der Beweis:
    https://ideone.com/Nqvldf (Sorry für C++, aber es ist schon in C++ ein übler Hack, den Namen eines Typen zu erhalten, in C kenne ich gar keine verlässliche Möglichkeit. Jedenfalls gelten in C++ exakt die gleichen Regeln für Array- und Zeigerdefinitionen, es ist also nicht so, dass das Ergebnis in C ein anders wäre. Hier noch der Beweis, dass die Typen in C zumindest unterschiedlich sind, wen nauch ohne Erklärung, was es genau für Typen sind: https://ideone.com/5AfxJT )

    Ich hoffe das zeigt auch CCat, dass er sich nicht von solchen Blendertricks wie deinen beeindrucken lassen sollte. Zur Erklärung an CCat: Den Typ *char[] gibt es wie schon gesagt nicht. Da fehlt die Information, wie groß das Array sein soll. Was mein werter Kollege gemacht hat, ist, dass er durch die Initialisierung den Compiler hat herausfinden lassen, wie groß das Array sein soll. Und der resultierende Typ ist durch etwas Biegen und Brechen auch kompatibel zu char** und kann diesem zugewiesen werden. Weil C recht lax ist, was implizite Konvertierungen angeht. Das Array wird nämlich als ein Zeiger auf sein erstes Element aufgefasst, wenn es einfach nur so dasteht. Und da sein erstes Element ein char* ist, ist das Resultat logischerweise ein char** .

    Das ist genauso wie etwas, das du sicherlich kennst:

    int array[] = {1,2,3};
    

    Da gibt es auch keinen Typ int[] . Der Compiler ist bloß so schlau, dass er rechts nachzählen kann, dass Array vom Typ int[3] sein muss, damit es passt.

    Im übrigen ist auch ein vollständiger Typ wie *char[3] ein Array von 3 Zeigern auf char, kein Zeiger auf ein Array von 3 chars! Das ist wahrscheinlich umgekehrt wie du denkst. Ein Zeiger auf ein Array von chars wäre z.B. char(*)[3] . Zu schreiben beispielsweise so:

    char (*pointer)[3];
    

    Aber auch da gibt es logischerweise keinen Typ char(*)[] , die Größen von Arrays müssen bekannt sein, damit der Typ vollständig ist!



  • CCat schrieb:

    Soweit so gut. Nur warum kann ich getlin() jetzt ein *char übergeben, obwohl die Methode ein **char verlangt? 😕

    Wo wird an getline ein *char übergeben?

    Bei dem Beispiel von Sepp wird die Adresse vom *char (nicht der Inhalt) übergeben (achte auf das &). In getline kommt dann ein **char an.



  • Furble Wurble schrieb:

    SeppJ schrieb:

    Furble Wurble schrieb:

    Noch die Version, wie sie Dir vielleicht vorschwebte:

    size_t t=1;
       char *gptr=malloc(1);
    
       getline(&gptr, &t, fd);
    
       free(gptr);
    

    (Oder malloc(0) mit t=0 - aber das wäre unnötig weit weg von Standard C.)

    Das wird explodieren. Oder zumindest sollte es das. Wenn das durchläuft, ist das purer Zufall.

    Was genau meinst Du?

    push


  • Mod

    Furble Wurble schrieb:

    Furble Wurble schrieb:

    SeppJ schrieb:

    Furble Wurble schrieb:

    Noch die Version, wie sie Dir vielleicht vorschwebte:

    size_t t=1;
       char *gptr=malloc(1);
    
       getline(&gptr, &t, fd);
    
       free(gptr);
    

    (Oder malloc(0) mit t=0 - aber das wäre unnötig weit weg von Standard C.)

    Das wird explodieren. Oder zumindest sollte es das. Wenn das durchläuft, ist das purer Zufall.

    Was genau meinst Du?

    push

    War doch richtig, ich hatte die Spezifikation von getline nicht richtig im Kopf, dass es automatisch ein free macht.


Log in to reply