2016-05-09 13 views
-1

Ich habe gesucht, wie ein dynamischer Puffer mit fgets zuweisen, aber ich kann nicht scheinen, um es in diesem Beispiel zu bekommen. Die Datei hat zwei Nummern unbekannter Länge, die durch einen Leerraum getrennt sind. Für jede Zeile liest es jedes Zeichen bis ' ' und \n und druckt es.Dynamische Puffer fgets in C

char *ptr; 
char line[MAX]; 

while(fgets(line, sizeof line , fp) != NULL){ 
    ptr = line; 
    for(i=0; i<2; i++){ 
     while(*ptr && (*ptr) != ' '){  
      if(*ptr == ' ') 
       break; 
      k = (*ptr) - '0'; 
      if(k != -38) // wont print '\n' 
       printf("%d", k);    
      ptr++; 
     } 
     while(*ptr && (*ptr) != '\n') { 
      if(*ptr == ' '){ 
       ptr++; 
       continue; 
      }  
      k = (*ptr) - '0'; 
      printf("%d", k);  
      ptr++; 
    } 
    } 
} 

Kann mir jemand eine Idee, wie line dynamisch zu machen, während noch ptr mit auf diese Weise?

+0

Was meinst du mit _dynamic_? Die Größe? Nun, das ist nicht möglich. Wenn Sie nicht die tatsächlichen Daten gelesen haben, wie werden Sie dann wissen, wie viel Speicher Sie benötigen? –

+0

Alle Möglichkeiten, die ich mir vorstellen kann, sind ziemlich ineffizient. – user3078414

+0

Sie sagen "dynamisch", was normalerweise bedeutet, dass Sie versuchen, einen beliebig großen Puffer für eine beliebig große Zeile dynamisch zuzuordnen, aber es sieht nicht so aus, als ob Sie das versuchen. –

Antwort

2

denke ich, was Sie wollen so etwas wie dieses:

size_t linelen = 80; 
char *line = malloc(linelen); 

while(magic_reallocating_fgets(&line, &linelen, fp) != NULL) { 
    /* ... do whatever you want with line ... */ 
} 

Aber dann ist natürlich die Frage $ 64.000, was wie magic_reallocating_fgets aussehen tut? Es ist so etwas wie folgt aus:

char *magic_reallocating_fgets(char **bufp, size_t *sizep, FILE *fp) { 
    size_t len; 
    if(fgets(*bufp, *sizep, fp) == NULL) return NULL; 
    len = strlen(*bufp); 
    while(strchr(*bufp, '\n') == NULL) { 
     *sizep += 100; 
     *bufp = realloc(*bufp, *sizep); 
     if(fgets(*bufp + len, *sizep - len, fp) == NULL) return *bufp; 
     len += strlen(*bufp + len); 
    } 
    return *bufp; 
} 

, die nicht wirklich vollständige Code ist, ist es fast Pseudo-Code. Ich habe zwei Dinge für Sie als Übungen verlassen:

Es hat keine Fehlerprüfung auf die malloc und realloc Anrufe.

Es ist ein bisschen grob ineffizient, in dem es nicht eine, sondern zwei zusätzliche Übergänge über jede Zeile liest es: um die Zeichen zu zählen, und wieder nach einem '\n' suchen. (Es stellt sich heraus fgets 's Schnittstelle ist nicht ideal für diese Art von Arbeit.)

+0

Deshalb ist 'fgetc' eine einfachere, elegantere und wahrscheinlich schnellere Lösung. –

+0

@CareyGregory Aber wenn du auf Effizienz achtest, benutze 'getc', nicht' fgetc'! –

+0

Ich verstehe. Ich benutze fgets, weil ich verschiedene Operationen mit den Zahlen abhängig von der Zeile machen muss, und es ist einfach, die Linie im Auge mit dieser Funktion zu verfolgen. –

0

Sie können die Größe eines Arrays während der Laufzeit in C nicht ändern. Es ist illegal. Dies liegt daran, dass Arrays vom Stapel zugewiesen werden. Um die Größe dynamisch zu machen, müssten Sie einen Zeiger deklarieren und den Speicher dafür dynamisch zuweisen. Diese Daten werden vom Heap zugewiesen.

Sie können die Größe des zugewiesenen Speichers ändern, indem Sie realloc verwenden.

int lineLen = 80; 
char *line; 
line = (char *)malloc(sizeof(char) * 80); 
if (line == NULL) { 
    // Something went horribly wrong 
    exit(1); 
} 
while (fgets(line, lineLen, fp)) { 
    // Do something to find the size 
    line = (char *)realloc(line, sizeof(char) * newLen); 
    if (line == NULL) { 
     // Something went horribly wrong 
     exit(1); 
    } 
} 

Die Zuweisung und Neuzuweisung von Speicher ist jedoch eine ziemlich teure Operation. Als Ergebnis können Sie effektiver sein, indem Sie einfach eine große Puffergröße auswählen, wenn Sie dies sicher tun können. Wenn Sie eine kurze Schleife haben, ist es vielleicht nicht signifikant genug, um sich Sorgen zu machen, aber es ist wahrscheinlich nicht ratsam, die Puffergröße ständig zu ändern.

+0

Nicht 'malloc' werfen. Sein Rückgabetyp ist 'void *', der implizit in einen beliebigen Zeigertyp konvertiert werden kann, so dass es keinen Sinn macht, ihn zu werfen. – Samadi

0

Auf Systemen mit glibc> = 2.7 oder POSIX.1-2008 Unterstützung, was ich denke, Sie können erreicht werden mit:

char *line; 
while (fscanf(f, "%m[^\n]\n", &line) == 1) { 
    /* do stuff with line */ 
    free(line); 
}