"Christmas - the time to fix the computers of your loved ones" « Lord Wyrm

ANSI C: Auslesen einer Datei in ein dynamisches Array

Neo-=IuE=- 30.11.2004 - 22:27 5600 14
Posts

Neo-=IuE=-

Here to stay
Registered: Jun 2002
Location: Berndorf, NÖ
Posts: 3232
Ich wollte eine Textdatei auslesen, aber ich wollte die Zeilen immer komplett haben, also zb mit fgets() kann ich ja nur "n-1" zeichen auslesen und brauch dafür aber auch wenn die zeile doch nur 5 zeichen lang ist ein "n" zeichenlanges char array
ich hab jetzt eine funktion geschrieben um das zu verwirklichen, dass es eben in ein dynamisch erstelltes array kommt...
nur kommt mir das a bissi umständlich vor.

Wenn jemand a bessere methode weiß, dann bitte postets es :)

Code:
// Zeilenweises Auslesen einer Textdatei und speichern der Zeile in ein dynamisch erstelltes Array

#include <stdio.h>
#include <stdlib.h>

int len(const char* string)
{
	int length = 0; // Zählvariable für Zeichenkettenlänge
	while(string[length]) // Bis Abschluss 0
		length++; // Position erhöhen
	return length; // Länge zurückgeben
}

int main(void)
{
	char *buf; // Pointer auf ausgelesene Zeile
	FILE *f; // Filepointer
	int length=0; // Zählvariable
	f = fopen("test.txt", "r"); // Öffnen der Testdatei
	if (!f) // Wenn File not found abbrechen
		return 1;
	while(!feof(f)) // Bis Fileende erreicht:
	{
		buf = (char*)malloc(sizeof(char*)); // Speicherplatz für erstes Zeichen reservieren
		buf[length] = fgetc(f); // Erstes Zeichen der Zeile auslesen
		while(!((buf[length]=='\n')||(!buf[length]))) // Bis Zeichen \n oder \0 ist:
		{
			length++; // Anzahl der Zeichen pro Zeile erhöhen
			buf = (char*)realloc(buf, sizeof(char*)*length); // Speicherplatz um 1 Zeichen verlängern
			buf[length] = fgetc(f); // Nächstes Zeichen auslesen
			if(feof(f)) // Bei Fileende Abbruchbedingung von Schleife setzen
				buf[length] = 0;
			if(buf[length-1] == EOF) //Wenn Zeichen für EOF ausgelesen wurde, dieses löschen
				buf[length-1] = 0;

		}
		if (buf[length] == '\n') // Wenn letztes Zeichen \n:
		{
			buf = (char*)realloc(buf, sizeof(char*)*(length+1)); // Speicherplatz um 1 Zeichen verlängern
			buf[length+1] = 0; // \0 für Zeilenende hinzufügen
		}
		printf("%s", buf); // Testausgabe der Zeile
		length = 0; // Länge rücksetzen
		free(buf); // Speicher wieder freigeben
	}
	fclose(f); // File schließen
	scanf("%c", &length); // Zeichen einlesen für warten vor Programmende
	return 0;
}
Bearbeitet von Neo-=IuE=- am 30.11.2004, 23:02

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25423
*) file 1x komplett mit einem fread auslesen.. es sei denn, dein textfile ist wirklich groß (> 100mb? O_o), dann lies es in größeren blöcken ein. allgemein gesagt: umso mehr du auf einmal liest, desto schneller :)

*) strchr das nach dem zeilenende sucht (entweder \r\n oder nur \n.. je nach os - brauchst aber eh nur nach \n suchen und dann jeweils ) und die zeile in eine linked list aufnimmt (braucht keine double ll sein, forwärts reicht ja).

ich hab zwar von realloc nichts schlechtes gehört, persönlich würd ichs aber meiden. kA, vl weiss wer andrer mehr dazu.

oder willst dus wirklich in einem char** haben?

edit: btw, es gibt strlen() :eek:

that

Moderator
Hoffnungsloser Optimist
Avatar
Registered: Mar 2000
Location: MeidLing
Posts: 11338
Ein realloc für jedes Zeichen = quadratisches Zeitverhalten der Funktion = schlecht.

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25423
für jedes zeichen :eek:

so genau hab ich gar nicht geschaut, hab nur realloc gesehen und gedacht es wird pro zeile vergrößert :)

Neo-=IuE=-

Here to stay
Registered: Jun 2002
Location: Berndorf, NÖ
Posts: 3232
na ich habs zeilenweise ausgelesen, zeile verarbeitet, dann erst nächste zeile

des mit strlen() is ma scho klar, des kommt aber noch daher, dass in der fh bei dem bsp wo wir grad sind wir die string.h net einbinden sollen, weil wir zb strstr() selba schreiben sollen

nur mir is des zfad, deshalb mach i mir halt selba aufgabenstellenungen und schau ob ich die sinnvoll lösen kann

ja des mim realloc gfällt ma ja eh net, nur wie sonst:
wie bei fgets() brauch auch fread ein char array des scho besteht um n zeichen reinzulesen... nur ich will eben keinen unnötign speicher reservieren :p
naja dann muss ichs doch so machen, dass ich imma in einen buffer einlese mit bestimmter anzahl von zeichen und dann aber in ein dynamisch erstelltes array verknüpfe für die zeile

Ringding

Pilot
Avatar
Registered: Jan 2002
Location: Perchtoldsdorf/W..
Posts: 4300
Zitat von mat
*) file 1x komplett mit einem fread auslesen.. es sei denn, dein textfile ist wirklich groß (> 100mb? O_o), dann lies es in größeren blöcken ein. allgemein gesagt: umso mehr du auf einmal liest, desto schneller :)
Allerdings ist fgetc auch recht schnell, und wenn er noch getc statt fgetc verwenden würde, wär's sogar fast gleich schnell wie ein größeres fread.

Ich würde es so machen: Zuerst einmal mit einem kleinen Array anfangen (1kb oder so). Wenn das reicht, realloc auf die richtige Größe und fertig. Wenn nicht, gehst du in eine Schleife, in der du dir eine Liste aus Arrays zusammenhängst, in die du immer das nächste Stück hineinliest, bis nichts mehr kommt. Dann weißt du die Gesamtgröße, kannst das Ergebnisarray anlegen, stückweise alles zusammenkopieren und die kleinen Arrays freigeben. Braucht zwar kurzzeitig die doppelte Menge an Speicher, aber das ist nicht unüblich - außerdem könnte dir das bei realloc ebenso passieren.

gue

Addicted
Avatar
Registered: Feb 2003
Location: Linz
Posts: 400
Zitat von Neo-=IuE=-
wie bei fgets() brauch auch fread ein char array des scho besteht um n zeichen reinzulesen... nur ich will eben keinen unnötign speicher reservieren :p
Hast du das probiert? Das stimmt nämlich nicht. fgets und fread reservieren den Speicher und geben einen Zeiger darauf zurück. Du brauchst da gar nichts allozieren ;)
Du kannst also durchaus fgets benutzen.
Edit:
pro forma dein Programm
Code:
#include <stdio.h>
#include <stdlib.h>

int main(void) {
	char *string;
	FILE *file;
	file = fopen("text.c", "r");
	while (!feof(file)) {
		if (fgets(string, 0xffff, file)) printf("%s", string);
	}
	fclose(file);
}

Ringding

Pilot
Avatar
Registered: Jan 2002
Location: Perchtoldsdorf/W..
Posts: 4300
Zitat von gue
fgets und fread reservieren den Speicher und geben einen Zeiger darauf zurück.
Unsinn.

Rektal

Here to stay
Registered: Dec 2002
Location: Inside
Posts: 4452
Zitat von gue
Zitat von Maxx666
->
Slide Card & Swap Magic Set

man fgets
Zitat
char *fgets(char *s, int size, FILE *stream);

fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s.

"pointed to by s" == selber buffer anlegen

Neo-=IuE=-

Here to stay
Registered: Jun 2002
Location: Berndorf, NÖ
Posts: 3232
eben
gue bei deiner variante hast glück, dass du nix wichtiges überschrieben hast beim einlesen ;)
sicha is a pointer auf char gleichwertig, nur wenn du den pointer nicht auf ein array legst bzw. auf ein mit malloc erstelltes array zeigen lässt, dann kannst du genauso irgendwas im ram überschreiben ;)

ich habs jetzt so gmacht, dass ich einfach ein array dynmisch erstellt hab mit einer bestimmten größe zb 100 und dann einfach imma um 100 vergrößert hab und immer mit fgets() einglesen und dann zamghängt
natürlich hab ich dann zwar a bissi unsinnig benützten speicherplatz, max. halt knapp 100byte ;)

gue

Addicted
Avatar
Registered: Feb 2003
Location: Linz
Posts: 400
Zitat von Ringding
Unsinn.
Stimmt :bash:

Sorry für Misinfo @ Neo (war wohl doch 1 Bier zu viel gestern :))

SYSMATRIX

Legend
Legend
Registered: May 2000
Location: ~
Posts: 5020
und warum nicht per mmap?

mmap dürfte locker 1.5x so schnell sein wie die methode per syscalls.

speichersparender dürfte es auch sein.

Ringding

Pilot
Avatar
Registered: Jan 2002
Location: Perchtoldsdorf/W..
Posts: 4300
Weil der Thread "ANSI C" heißt.

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25423
Zitat von SYSMATRIX
und warum nicht per mmap?

mmap dürfte locker 1.5x so schnell sein wie die methode per syscalls.

speichersparender dürfte es auch sein.
mach lieber perl, webjunge :D :p

SYSMATRIX

Legend
Legend
Registered: May 2000
Location: ~
Posts: 5020
edit: sorry, my bad :/
@mat:
fu! :D
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz