Dateiinhalt als char
-
Die Anzahl der Zeichen lässt sich per Dateiinformationen ermitteln, z.B. fstat und co..
Ermitteln lässt sich sich auch ohne Dateiinfos mit fseek/ftell oder zeichenweises Einlesen und zählen der Zeichen.
Brauchst du den Text komplett im Arbeitsspeicher, kommst du ab einer bestimmten Anzahl Bytes nicht um malloc drum herum:
char* b = malloc ( anzahl_der_zeichen + 1);
Es funktioniert auch ohne sich im Voraus um die Anzahl der Zeichen in der Datei zu kümmern, indem das Array mit realloc dynamisch erweitert wird.
-
Oder halt ueber verkettete Liste, die dann in einen String geschrieben wird - etwa so (ins Grobe geschmiert):
struct SingleChar { char cData; struct SingleChar *pNext; } struct SingleChar *ReadList (FILE *pFile) { struct SingleChar *pCurrent = NULL, *pReturn = NULL, *pTemp; char cTemp; while (!feof(pFile)) { pTemp = malloc (sizeof (SingleChar)); pTemp->cData = fgetc(pFile); pTemp->pNext = NULL; if (pReturn == NULL) pReturn = pTemp; else pCurrent->pNext = pTemp; pCurrent = pTemp; } return pReturn; } void FillData (char *szText, struct SingleChar *pIn) { szText [0] = pIn->cData; if (pIn->pNext != NULL) FillData (&szText [1], pIn->pNext); else szText [1] = '/0'; } int GetCount (struct SingleChar *pIn, int iValue) { if (pIn == NULL) return iValue; else return (GetCount->pNext, iValue + 1); } char *BuildStr (struct SingleChar *pIn) { char *szReturn; szReturn = calloc (GetCount (pIn, 0) + 1, sizeof (char); FillData (szReturn, pIn); return szReturn; } int main () { FILE *pFile = NULL; struct SingleChar *pCharList = NULL; char *szOut = NULL; pFile = fopen("text.txt", "r"); if (pFile != NULL) pCharList = ReadList (pFile); if (pCharList != NULL) szOut = BuildStr (pCharList); if (szOut != NULL) printf ("My text: <%s>\n", szOut); else printf ("Schiefgegangen\n"); if (szOut != NULL) free (szOut); if (pFile != NULL) fclose (pFile); CleanList (pCharList); return 0; }
-
hartmut, dein beispiel ist absoluter overkill.
-
@hartmut: ehrlich gesagt, finde ich das unnötig kompliziert und Speicherfressend. Eine ganze Struktur für jedes Zeichen finde ich ganz schon übertrieben.
Ich verwende immer
char *get_next_line(FILE *fp) { int c, buff_len, str_len; char *buff, *tmp; buff = NULL; buff_len = str_len = 0; for(c = fgetc(fp); (c != '\n' && c != EOF) ; c = fgetc(fp)) { str_len++; if(str_len >= buff_len) { buff_len = 2*str_len; tmp = realloc(buff, buff_len); if(tmp == NULL) return buff; buff = tmp; } buff[str_len - 1] = c; buff[str_len] = 0; } return buff; }
um Zeilen zu lesen, daraus eine get_file_content() Funktion zu basteln, sollte nicht schwer sein.
-
supertux schrieb:
for(c = fgetc(fp); (c != '\n' && c != EOF) ; c = fgetc(fp))
das sieht aber hässlich aus. mach doch 'ne do..while daraus.
-
+fricky schrieb:
supertux schrieb:
for(c = fgetc(fp); (c != '\n' && c != EOF) ; c = fgetc(fp))
das sieht aber hässlich aus.
finde ich nicht aber Geschmack ist subjektiv.
so, hab auch ne get_file_content mit dazu passender free Funktion geschrieben:
/* returns NULL terminated list of char* Pointers */ char **get_file_content(FILE *fp) { char **buff, **tmp, *line; int len = 0; buff = calloc(1, sizeof *buff); if(buff == NULL) return NULL; buff[0] = NULL; while(line = get_next_line(fp)) { tmp = realloc(buff, (len+2) * sizeof *buff); if(tmp == NULL) return buff; buff = tmp; buff[len++] = line; buff[len] = NULL; } return buff; } void free_file_content(char **fc) { int i = 0; if(fc == NULL) return; while(fc[i]) free(fc[i++]); free(fc); }
-
^^lass es vom mod in die faq aufnehmen.
-
supertux schrieb:
@hartmut: ehrlich gesagt, finde ich das unnötig kompliziert und Speicherfressend. Eine ganze Struktur für jedes Zeichen finde ich ganz schon übertrieben.
Semi Off-Topic:
Kompliziert - OK: War auch nicht ganz ernst gemeint.
Speicherintensiv: Weniger, die Struct enthaelt nur einen char und einen Pointer. Das verdoppeln des Heaps ("buff_len = 2*str_len; tmp = realloc(buff, buff_len);") ist u.U. sehr viel speicherintensiver.---
Das Problem mit meinem Vorschlag ist ein anderes: Die Rekursion wird ueber den Stack abgehandelt, wenn z. B. ueber 10^6 Elemente eingelesen werden, geht dieser dann schon mal in die Knie und Du hast einen Stackoverflow. Und hier wuerde ich Pruegel verdientermassen einstecken muessen.
-
hartmut1164 schrieb:
Und hier wuerde ich Pruegel verdientermassen einstecken muessen.
allein schon die idee, eine ganze datei zeichenweise in eine verkettet liste zu verwandeln, ist der pure wahnsinn. mach doch demnächst pro zeichen ein unterverzeichnis (das zeichen selbst ist dann der name einer einzigen datei im verzeichnis).
-
+fricky schrieb:
hartmut1164 schrieb:
Und hier wuerde ich Pruegel verdientermassen einstecken muessen.
allein schon die idee, eine ganze datei zeichenweise in eine verkettet liste zu verwandeln, ist der pure wahnsinn.
Nicht ganz: Hier ist das mit Kannonen auf Spatzen geschossen, aber wenn Du Dir einmal einen Datenfile einliesst, z. B. ueber einen Socket, und weisst nicht wie gross die Datenmengen sind, willst aber direkt eine Rueckmeldung geben, falls inconsitente Daten uebertragen werden, dann muss man solche Listen und deren Zeigerverknuepfung dynamisch beim Einlesen aufbauen.
-
hartmut1164 schrieb:
Semi Off-Topic:
Kompliziert - OK: War auch nicht ganz ernst gemeint.
Speicherintensiv: Weniger, die Struct enthaelt nur einen char und einen Pointer. Das verdoppeln des Heaps ("buff_len = 2*str_len; tmp = realloc(buff, buff_len);") ist u.U. sehr viel speicherintensiver.Bei
n
Zeichen fordertget_next_line
maximal2*n
Bytes an (
Bytes um genau zu sein)Bei
n
Zeichen fordertReadList
genausizeof(struct SingleChar)*n
Bytes an, was ja8*n
Bytes bedeutet (wegen Padding Bytes). Und du nennst meine Methode speicherintensiver? (außerdem habe ich ~log_2(n)
malloc/realloc Aufrufe und du genaun
)edit:
+fricky schrieb:
^^lass es vom mod in die faq aufnehmen.
gute Idee, hab den Code schon öfters hier gepostet.
-
hartmut1164 schrieb:
...aber wenn Du Dir einmal einen Datenfile einliesst, z. B. ueber einen Socket, und weisst nicht wie gross die Datenmengen sind, willst aber direkt eine Rueckmeldung geben, falls inconsitente Daten uebertragen werden, dann muss man solche Listen und deren Zeigerverknuepfung dynamisch beim Einlesen aufbauen.
nö, das könnteste genau so machen wie z.b. mit supertuxens realloc-methode. wobei ich sowieso mehr ein fan von häppchenweiser verarbeitung bin. komplettes einlesen von datenmengen, die beliebig gross sein können, ist immer gefährlich (ausser man setzt sich ein limit).