Probleme beim Auslesen einer Datei



  • Du könntest in deiner Funktion ein Array erstellen, in das du deine ganzen Daten kopierst und ganz am Ende einfach den Pointer auf das Array zurückgeben. sähe dann etwa so aus:

    char ** getTitles (FILE * f)
    {  char ** Zwischenspeicher = malloc ( 100 * sizeof(char * )); /*falls du weißt, wie groß dein Array werden soll, mach es so - und übergib die nötige Größe vielleicht noch an die Funktion*/
       ...
       return(Zwischenspeicher);
    }
    
    int main()
    {  char ** Datenfeld;
       char *pfad = "./data.txt";
       FILE f = fopen(Pfad , "r");
       ...
       Datenfeld = getTitles(f);  //danach hast du dein Array
       ...
    }
    

    Solltest du ein völlig dynamisches Array haben wollen, musst du in deiner getTitles-Funktion wohl ein paar reallocs einbauen, momentan dürfte deine Datei genau 100 Zeilen zu je maximal 100 Zeichen haben.



  • klopf-klopf schrieb:

    Dann hab ich aber das Problem das ich das Array nicht mehr in der main() benutzen kann.
    (OK, ich habs oben nicht erwähnt ;)).
    Der Speicherplatz des Array's würde ja dann sobald die Funktion beendet würde, wieder freigegeben.

    Doch, das kannst du auch in der main benutzen. Zugriff auf Speicher, der mit malloc und co. reserviert ist, geht überall im Programm. Erst ein free oder Überschreiben des Zeigers macht es unmöglich.

    klopf-klopf schrieb:

    Verstehe ich das richtig, das alles gehen würde sobald das Array korrekt intialisiert wäre?

    Nee, da sind noch ein paar Ergänzungen nötig.

    Ist eigentlich die Anzahl der Zeilen im Voraus bekannt? Wenn nicht:

    char** getTitles (FILE* fp, int* n);
    

    Die Variable n soll die Anzahl der Zeilen Speichern.



  • Stiefel2000 schrieb:

    Du könntest in deiner Funktion ein Array erstellen, in das du deine ganzen Daten kopierst und ganz am Ende einfach den Pointer auf das Array zurückgeben. sähe dann etwa so aus:

    char ** getTitles (FILE * f)
    {  char ** Zwischenspeicher = malloc ( 100 * sizeof(char * )); /*falls du weißt, wie groß dein Array werden soll, mach es so - und übergib die nötige Größe vielleicht noch an die Funktion*/
       ...
       return(Zwischenspeicher);
    }
    
    int main()
    {  char ** Datenfeld;
       char *pfad = "./data.txt";
       FILE f = fopen(Pfad , "r");
       ...
       Datenfeld = getTitles(f);  //danach hast du dein Array
       ...
    }
    

    Solltest du ein völlig dynamisches Array haben wollen, musst du in deiner getTitles-Funktion wohl ein paar reallocs einbauen, momentan dürfte deine Datei genau 100 Zeilen zu je maximal 100 Zeichen haben.

    Reallocs koennen auch vermieden werden:

    #if (MAX_PATH_LEN == 1024)
     #define MAX_PATH_LEN_MINUS_1 1023
    #else
     #error Check MAX_PATH_LEN
    #endif
    
    typedef struct SingleLine {
        char        *szLine;
        SingleLine  *pNext   = NULL;
    };
    
    SingleLine *CreateNewTile (const char *szLine)
    {
        SingleLine *pReturn;
    
        pReturn = malloc (sizeof (SingleLine));
    
        if (pReturn == NULL)
        {
            fprintf (stderr, "Can not alloc heap 1\n");
            abort ();
        }
        else
        {
            pReturn->szLine = calloc (strlen (szLine) + 1, sizeof (char));
            if (pReturn->szLine == NULL)
            {
                fprintf (stderr, "Can not alloc heap 1\n");
                abort ();
            }
            else
                strncpy (pReturn->szLine, szLine)
        }
    
        return pReturn;
    }
    
    SingleLine *ReadTile (FILE   *pSource)
    {
        SingleLine  *pReturn  = NULL,
                    *pCurrent = NULL,
                    *pTemp;
        char        *szLine   [MAX_PATH_LEN];
    
        while ((fgets (szLine, MAX_PATH_LEN_MINUS_1 , pSource) != NULL) &&
               (fSuccess == true))
        {
            pTemp = CreateNewTile (szLine);
            if (pReturn == NULL)
                pReturn = pTemp;
            else
                pCurrent->Next = pTemp;
    
            pCurrent = pTemp;
        }
    
        return pReturn;
    }
    
    SingleLine  *GetTitles (const char *szFilename)
    {
        FILE       *pSource = NULL;
        SingleLine *pReturn = NULL;
    
        pSource = fopen (szFilename, "r");
        if (pSource == NULL)
            fprintf ("Can not open <%s>; code <%d>; mssg <%s>\n", 
                            errno, strerror (errno));
        else        
        {
            pReturn = ReadTile (pSource);
            fclose (pSource);
        }
    
        return pReturn;
    }
    
    int main ()
    {
        SingleLine  *pTiles = NULL;
    
        pTiles *GetTitles ("/in/Den/Tiefen/Des/FS.dat");
    
    /* mehr */
    }
    

    Damit ist die Verwaltung der Daten sehr flexible und kann jederzeit angepasst werden.



  • hartmut1164 schrieb:

    Reallocs koennen auch vermieden werden:

    ist ja keine kunst, wenn man mit festen längen arbeitet, wie mit deinem MAX_PATH_LEN.
    🙂



  • hartmut1164 schrieb:

    ...

    Hat es einen Grund, dass Du allokierte Ressourcen im Fehlerfall nicht wieder frei gibst?



  • Tachyon schrieb:

    hartmut1164 schrieb:

    ...

    Hat es einen Grund, dass Du allokierte Ressourcen im Fehlerfall nicht wieder frei gibst?

    Ich benutze ein abort () - das hat etwas die gleiche Wirkung SIGKILL; da wird freigeben. Da passiert aber nur, wenn kein neuer Heap mehr allociert werden kann.



  • +fricky schrieb:

    hartmut1164 schrieb:

    Reallocs koennen auch vermieden werden:

    ist ja keine kunst, wenn man mit festen längen arbeitet, wie mit deinem MAX_PATH_LEN.
    🙂

    MAX_PATH_LEN begrenzt nur die Laenge des Einlesestrings aus dem File. Der String selber wird hier allociert:

    pReturn->szLine = calloc (strlen (szLine) + 1, sizeof (char));
    


  • hartmut1164 schrieb:

    Tachyon schrieb:

    hartmut1164 schrieb:

    ...

    Hat es einen Grund, dass Du allokierte Ressourcen im Fehlerfall nicht wieder frei gibst?

    Ich benutze ein abort () - das hat etwas die gleiche Wirkung SIGKILL; da wird freigeben.....

    Wie kommst Du auf die abstruse Idee? Da wird nichts freigegeben, es sei denn, das OS oder die Implentierung des Compilers tut das rein zufällig. Da kann und sollte man sich aber nicht drauf verlassen.
    Einen Heap gibts in C btw. nicht. Und was soll SIGKILL sein? Du meinst sicher SIGABRT.



  • Tachyon schrieb:

    Ich benutze ein abort () - das hat etwas die gleiche Wirkung SIGKILL; da wird freigeben.....

    Wie kommst Du auf die abstruse Idee? Da wird nichts freigegeben, es sei denn, das OS oder die Implentierung des Compilers tut das rein zufällig. Da kann und sollte man sich aber nicht drauf verlassen.[/quote]

    Gebe zu, abort () erzeugt nicht SIGKILL, sondern SIGABRT. Wenn das OS aus irgentwelchen Gruenden keinen Speicher mehr zur Verfuegung stellen kann (z. B. malloc nicht mehr funktioniert), passiert etwas ziemlich uebles. In diesen Falle tut man gut daran das Programm zu schnell und brutal als moeglich zu beenden. Der Vorteil des abort () ist dabei, dass es einen Core schreibt, den man auswerten kann; was bei einer solchen Fehlfunktion sehr sinnvoll ist.

    Edit: Der Hauptunterschied zwischen SIGKIL und SIGABRT ist, dass eine nicht vom Prozess selber abgefangen werden kann, was aber nicht noetig ist, da SIGABRT vom Prozess selber geworfen wird.

    Tachyon schrieb:

    Einen Heap gibts in C btw. nicht.

    Acht und wo stehen in beiden Beipielen meine 100'000 chars?

    char   szLine_0 [100000];
    char  *szLine_1;
    
    szLine_1 = calloc (100000, sizeof (char));
    

    Bei szLine_0 stehen im Stack und werden bei der Beendigung des Block wieder freigeben, bei szLine_1 steht nur erste Adresse auf den allocierten Bereich im Stack, waerend die 100'000 char in Heap stehen, d. h. die der Speicherplatz der Adresse wird bei der Beendigung des Blocks wieder freigeben, nicht aber der Bereich im Heap, auf den diese zeigt - weshalb man das ganze in den meisten Faellen auch macht.



  • hartmut1164 schrieb:

    In diesen Falle tut man gut daran das Programm zu schnell und brutal als moeglich zu beenden.

    Aber nicht, ohne vorher erfolgreich angeforderte Ressourcen wieder freizugeben.
    Wenn Du ein OS hast (vielleicht gibt es auch kein OS), welches einem nicht hinterher räumt, bekommt man sonst recht schnell Probleme. Und je nach Ressource kann es auch sein, dass selbst das OS nichts machen kann.
    Und ob "was ziemlich Übles" passiert, wenn kein Speicher mehr zur Verfügung steht, hängt stark vom Programm ab. Erstmal schlagen einfach Anforderungen fehl. Das ist so erstmal kein Grund für einen abort.

    hartmut1164 schrieb:

    Edit: Der Hauptunterschied zwischen SIGKIL und SIGABRT ist, dass eine nicht vom Prozess selber abgefangen werden kann, was aber nicht noetig ist, da SIGABRT vom Prozess selber geworfen wird.

    SIGKILL gibt es gar nicht. Es gibt höchstens SIGTERM.

    hartmut1164 schrieb:

    Tachyon schrieb:

    Einen Heap gibts in C btw. nicht.

    Acht und wo stehen in beiden Beipielen meine 100'000 chars?

    In 'nem Speicher mit Allocated Storage Duration. Heaps und Stacks gibt es im C-Standard nicht wirklich, weil dort ziemlich konkrete Datenmodelle hinterstehen.



  • Tachyon schrieb:

    hartmut1164 schrieb:

    In diesen Falle tut man gut daran das Programm zu schnell und brutal als moeglich zu beenden.

    Aber nicht, ohne vorher erfolgreich angeforderte Ressourcen wieder freizugeben.
    Wenn Du ein OS hast (vielleicht gibt es auch kein OS), welches einem nicht hinterher räumt, bekommt man sonst recht schnell Probleme. Und je nach Ressource kann es auch sein, dass selbst das OS nichts machen kann.

    Es gehoert seit dem IBM/360 zu grundlegenden Aufgaben eines OS die Allocierung von Resourcen durch Prozesse zu steuern, sich diese Resourcen "zu merken" und diese ggf. wieder freizugeben.

    Das mag bei der Kernel-Prg. anders sein, aber das ist eher "Randbereich - wenn auch ein extrem wichtiger.

    Tachyon schrieb:

    Und ob "was ziemlich Übles" passiert, wenn kein Speicher mehr zur Verfügung steht, hängt stark vom Programm ab. Erstmal schlagen einfach Anforderungen fehl. Das ist so erstmal kein Grund für einen abort.

    Ich saehe nur zwei Szenarien, wo ich das nicht machen wuerde:

    1. Bei extrem beschraeckten Resourcen (z. B. im embedded Bereich)
    2. Bei sehr grossen angeforderten Datenmengen

    Selbst bei heutigen Feld-Wald-und-Wiesen-Rechnern mit nahezu unbegrenzten Resourcen im Arbeitsspeicher von 100/1000en von MB erscheint mit Szenario 2) in den meisten Faellen wirklich unwahrscheinlich (gibt auch Ausnahmen, aber das sind Ausnahmen).

    Tachyon schrieb:

    SIGKILL gibt es gar nicht. Es gibt höchstens SIGTERM.

    Steht im Posix-std.; ist bei Linux Signal 9

    Tachyon schrieb:

    Einen Heap gibts in C btw. nicht.

    hartmut1164 schrieb:

    Acht und wo stehen in beiden Beipielen meine 100'000 chars?

    In 'nem Speicher mit Allocated Storage Duration. Heaps und Stacks gibt es im C-Standard nicht wirklich, weil dort ziemlich konkrete Datenmodelle hinterstehen.[/quote]

    Das ergibt sich aus der praktischen Implementation als sequenzielle Abarbeitung der localen Variablen (und Uebergabeattribute) und der dynamischen Verwaltung des z.B. ueber malloc allocierten Speichers. Ich will nicht bezweifeln, dass man das auch anders implementieren kann (heap/Stack), wuesste aber nicht wie.



  • hartmut1164 schrieb:

    Es gehoert seit dem IBM/360 zu grundlegenden Aufgaben eines OS die Allocierung von Resourcen durch Prozesse zu steuern, sich diese Resourcen "zu merken" und diese ggf. wieder freizugeben.

    Was ist mit µC, DSPs etc.? Die haben i.d.R. kein OS, das Dir hinterher räumt. Solche Plattformen werden recht oft benutzt und sind weder ein Randbereich noch sonderlich exotisch.
    Selbst unter Windows gibt es einige Ressourcen, die nicht wieder freigegeben werden, wenn der zugehörige Prozess stirbt. Einige GDC-Handles z.B.

    hartmut1164 schrieb:

    Steht im Posix-std.; ist bei Linux Signal 9

    Und was hat Posix mit ANSI-C zu tun?

    hartmut1164 schrieb:

    Ich will nicht bezweifeln, dass man das auch anders implementieren kann (heap/Stack), wuesste aber nicht wie.

    Das glaube ich Dir sofort. 😉



  • Tachyon schrieb:

    Selbst unter Windows gibt es einige Ressourcen, die nicht wieder freigegeben werden, wenn der zugehörige Prozess stirbt. Einige GDC-Handles z.B.

    meinste GDI-handles? das war mal zur zeit der 16-bit windosen, win98, win-me und so. die nt-abkömmlinge räumen alles sauber wieder weg.
    🙂



  • +fricky schrieb:

    Tachyon schrieb:

    Selbst unter Windows gibt es einige Ressourcen, die nicht wieder freigegeben werden, wenn der zugehörige Prozess stirbt. Einige GDC-Handles z.B.

    meinste GDI-handles? das war mal zur zeit der 16-bit windosen, win98, win-me und so. die nt-abkömmlinge räumen alles sauber wieder weg.
    🙂

    Ne, ich meine eher sowas wie Icon-Handles. Da steht sogar explizit dabei, dass die nicht wieder weggeräumt werden.



  • Tachyon schrieb:

    Ne, ich meine eher sowas wie Icon-Handles. Da steht sogar explizit dabei, dass die nicht wieder weggeräumt werden.

    kann ich mir nicht vorstellen, haste 'nen link?
    🙂



  • +fricky schrieb:

    Tachyon schrieb:

    Ne, ich meine eher sowas wie Icon-Handles. Da steht sogar explizit dabei, dass die nicht wieder weggeräumt werden.

    kann ich mir nicht vorstellen, haste 'nen link?
    🙂

    Jo hast recht. Das war wirklich zur Prä-NT-Ära. Ich habe schon 'ne Weile nichts mehr mit der Win-API gemacht. Auf jeden Fall isses aber neuer als IBM/360.
    Die Funktionen waren LoadIcon, CreateIcon etc.



  • Hallo zusammen!
    Vielen Dank für eure Hilfe!
    Leider stehe ich aber irgendwie immer noch aufm Schlauch.
    Ich bekomme immer noch den "Segmentation fault"-Fehler.

    Hab meine Datei mal ausgemistet und aufs nötigste reduziert:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    
    char **getTitles(int *n){
    	char *pfad = "./data.txt";
    	char **titles = (char**)malloc(20*sizeof(char * ));
    	char *c;
    	FILE *f;
    	int i = 0;
    	f = fopen(pfad, "r");
            if(f==NULL) {
                perror("Error: can't open file.\n");
                }else{
                while(fgets(c, 95, f)!=NULL && i<20) {
    		titles[i] = (char*)malloc(96 * sizeof(char));
                    strncpy(titles[i],c,95);
                    i++;
                }
                fclose(f);
    	    *n = i+1;
    	    return titles;
            }
    }
    
    int main(void){
    	int *cntTitles = 0;
    	char **titles = getTitles(cntTitles);
    	int i;
    
    	for(i=0;i<*cntTitles;i++){
    		printf("%s", titles[i]);
    	}
    
    	for(i=0;i<*cntTitles;i++){
    		free(titles[i]);
    	}
    	free(titles);
    	return EXIT_SUCCESS;
    }
    

    Was ist daran noch falsch?

    Grüsse klopf-klopf



  • Auf was zeigt denn Dein Pointer c ?



  • while(fgets(c, 95, f)!=NULL && i<20) {
    titles[i] = (char*)malloc(96 * sizeof(char));
    strncpy(titles[i],c,95);
    i++;
    }
    

    auf den String der fgets() eingelesen hat. (Oder?)

    Grüsse klopf-klopf



  • klopf-klopf schrieb:

    while(fgets(c, 95, f)!=NULL && i<20) {
    titles[i] = (char*)malloc(96 * sizeof(char));
    strncpy(titles[i],c,95);
    i++;
    }
    

    auf den String der fgets() eingelesen hat. (Oder?)

    Grüsse klopf-klopf

    fgets braucht einen Puffer, in den eingelesen wird. c zeigt aber nicht auf einen Puffer, sondern irgendwo hin.


Anmelden zum Antworten