fgets mit Zeigerarray?
-
Ich möchte eine Textdatei zeilenweise mit fgets lesen. Bei den Beispielen, die ich gefunden habe, wird dazu ein Array der folgenden Art benutzt:
char text[200][100];
für maximal 200 Zeilen mit maximal knapp 100 Zeichen. Ok, das funktioniert. Was mich stört, ist, dass für den Maximalfall Speicher bereitgestellt werden muss. Ich würde viel lieber
char *text[200]
benutzen und vor dem Einlesen der Zeile den wirklich benötigten Speicher mit malloc freimachen. Dazu muss ich aber wissen, wie lang die einzulesende Zeile ist. Gut, ich kann pro Zeile z.B. immer 100 Zeichen bereitstellen, oder ich speicher die Zeile irgendwo zwischen und habe dann die Länge. Gibt es einen eleganteren Weg?
Reinhard
-
Unter C - nein. Du mußt vor dem Aufruf wissen, wieviel Platz du zur Verfügung stellen mußt (und fgets() mitteilen, wieviel Platz du hast).
Unter C++ - std::string verwenden.
-
klare Verhältnisse, danke. Da bleibt nicht das Gefühl zurück, man könnte es noch besser machen.
-
Naja, man könnte mit malloc/realloc leicht etwas ähnliches zu std::string bauen.
-
Hab da mal kurz was gebastelt und auch nur kurz getestet, also mit Vorsicht geniessen.
#include <stdio.h> #include <stdlib.h> char *get_str(void); int main(void){ char *str; str = get_str(); if(str){ puts(str); // we need to free memory for str free(str); } else{ fputs("Error: out of memory", stderr); } return 0; } char *get_str(void){ char *buffer, *tmp; char letter; size_t size = 64; size_t i = 0; // get initial buffer buffer = malloc(size); if(!buffer){ return NULL; } // abort input with <Enter> while( (letter = fgetc(stdin)) != '\n' ){ // if buffer still large enough if( i < size-1 ){ buffer[i++] = letter; } // if buffer is full, double its capacity else{ size *= 2; tmp = realloc(buffer, size); // if realloc fails we need to free the old buffer if(!tmp){ free(buffer); return NULL; } else{ buffer = tmp; buffer[i++] = letter; } } } // terminate string buffer[i] = '\0'; // free unused memory size = i+1; buffer = realloc(buffer, size); // return return buffer; }
-
TactX schrieb:
... // free unused memory size = i+1; buffer = realloc(buffer, size); // return return buffer; }
// free unused memory return (tmp = realloc (buffer, size+1)) ? tmp : buffer;
-
Also ich halte es ja für extrem unwahrscheinlich, dass das einen Unterschied machen könnte, aber ich weiss ja nicht wie du realloc() implementierst
-
TactX schrieb:
Also ich halte es ja für extrem unwahrscheinlich, dass das einen Unterschied machen könnte, aber ich weiss ja nicht wie du realloc() implementierst
oben in der schleife machst du es ja anders,
bei '// if realloc fails we need to free the old buffer'
-
Ja, weil es da ja sein kann, dass realloc() fehlschlägt weil ich mehr Speicher anfordere. Aber unten gebe ich ja nur bekannt, dass ich einen Teil des reservierten Speichers nicht mehr brauche. Da ist es extrem unwahrscheinlich, dass dies schiefgeht. Müsste schon eine Arg miese Implementierung sein.
-
TactX schrieb:
Aber unten gebe ich ja nur bekannt, dass ich einen Teil des reservierten Speichers nicht mehr brauche. Da ist es extrem unwahrscheinlich, dass dies schiefgeht.
ich glaub' viele reallocs sehen einfach nur so aus:
void *realloc (void *old, size_t size) { void *new = malloc (size); if (new) { memcpy (new, old, size); free (old); } return new; }
-
Das wäre ja schon arg beschissen.
Edit: Aber im Endeffekt hast du recht, man sollte immer von bescheidenen Implementierungen ausgehen.