Probleme mit Speicherplatz-Reservierung



  • Hallo Leute,
    ich habe eine Funktion die mehrere Wörter aus einer Textdatei ließt und diese dann in ein Array von Zeichenketten speichern soll.

    Hierbei habe ich allerdings ein paar Probleme:

    Problem 1: Ich weiß nicht wie ich den Speicherplatz reserviere für meine eingelesenen Wörter und das Array.

    Problem 2: Immer wenn ich ein Wort ausgeben will gibt er mir nur das zuletzt eingelesene Wort an.

    In meiner Datei steht folgendes:

    mychar
    sometests
    blubf

    Mein Code sieht aus wie folgt:

    #include <stdio.h>
    #include <string.h>
    #include <malloc.h>
    #define MAX 3
    #define MAXLEN 100
    
    void liesDatei(char* DATNAME, char** Array);
    
    void liesDatei(char * Dateipfad, char ** Array)
    {
        FILE * datei;
        datei = fopen(Dateipfad,"r");
        //Array = calloc(10, sizeof(char*));
        if(datei)
        {
            char Buffer[MAXLEN + 2] = {0};
            int i = 0;
            //Array = malloc(sizeof(char*));
            while(fgets(Buffer,(MAXLEN),datei))
            {
                *(Array+i) = calloc(1,strlen(Buffer));
                if(*(Array+i)){
                    strcpy(*Array,Buffer);
                    i++;
                }
    
            }
        }
        fclose(datei);
    }
    
    int main()
    {
      char **ArrayZeiger = NULL;
    
      liesDatei("E:\\TestEinlesen\\Testeinlesen\\Test.txt", &ArrayZeiger);
      //soll das erste Wort in ArrayZeiger printen
      printf("%s\n",(ArrayZeiger));
    
        return 0;
    }
    

    Ich bin gerade echt ratlos, da ich normalerweise mit JAVA programmiere und ich mit dieser Zeigerschreibweise und Speicherplatzreservierung von C noch nicht zurecht komme 😕

    Bin für jede Hilfe dankbar..



  • Dein ArrayZeiger in main ist ein char** .
    Du übergibst die Adresse davon an liesDatei .
    Also kommt es in liesDatei ein char*** an.

    strlen liefert die Länge der Zeichenkette ohne die abschließende '\0'
    strcpy kopiert die aber mit.
    Also musst du beim speicherholen ein Byte mehr besorgen.

    Und wenn du für (Array+i) Speicher holst, den String aber nach (Array) kopierst, kann das nichts werden.

    Wenn du das alles geklärt hast (achte auf die anzahl der ***), kannst du auch mal Überlegen, warum dein printf in Zeile 40 so nicht funktioniert.

    Nebenbei sollte der Compiler da auch Warnungen ausspucken.



  • Das mit den *** verstehe ich nicht so ganz, heißt das ich müsste das im Endeffekt so aufschreiben?

    void liesDatei(char * Dateipfad, char ** Array)
    {
        FILE * datei;
        datei = fopen(Dateipfad,"r");
        *Array = calloc(10, sizeof(char)*100);
        if(datei)
        {
            char Buffer[MAXLEN + 2] = {0};
            int i = 0;
            //Array = malloc(sizeof(char*));
            while(fgets(Buffer,(MAXLEN),datei))
            {
                *(*(Array+i)) = calloc(1,strlen(Buffer)+1);
                if(*(*(Array+i))){
                    strcpy(*(*(Array+i)),Buffer);
                    i++;
                }
            }
        }
        fclose(datei);
    }
    

    Da stürzt er bei mir immer ab...

    void liesDatei(char * Dateipfad, char ** Array)
    {
        FILE * datei;
        datei = fopen(Dateipfad,"r");
        *Array = calloc(10, sizeof(char)*100);
        if(datei)
        {
            char Buffer[MAXLEN + 2] = {0};
            int i = 0;
            //Array = malloc(sizeof(char*));
            while(fgets(Buffer,(MAXLEN),datei))
            {
                *(Array+i) = calloc(1,strlen(Buffer)+1);
                if(*(Array+i)){
                    strcpy(*(Array+i),Buffer);
                    i++;
                }
            }
        }
        fclose(datei);
    }
    

    So hingegen bekomme ich mit dem Befehl

    printf("%s\n",(ArrayZeiger))

    mein erstes Element "mychar" raus.

    Meine Fragen hierzu:

    Was muss ich beachten da ich hier ja nur die Adresse von einem char** bekommen hab (bzw einen Zeiger auf char**).

    Ist meine Speicherreservierung *Array = calloc(10, sizeof(char)*100); hierbei Richtig wenn das Array maximal 10 Zeichenketten enthalten darf und jene 100 Zeichen lang sein dürfen?

    Wenn printf("%s\n",(ArrayZeiger)) falsch ist, wie lautet es richtig?
    Ich hatte erst an printf("%s\n",*(ArrayZeiger)) gedacht, aber dann stürzt mir die Console immer ab...



  • Nerethar schrieb:

    Das mit den *** verstehe ich nicht so ganz...

    Warum gibst du nicht einfach das Array aus der Funktion zurück?

    (unsigned* n: eventuell möchte man die Anzahl der Zeichenketten wissen,
    nicht zuletzt weil reservierter Speicher freigegeben werden sollte,
    auf manchen Systemen sogar freigegeben werden muss.)

    char** read_file ( const char* fname, unsigned* n )
    {
    	char** words;
       unsigned anzahl_zeichenketten;
    	FILE* fp = fopen ( fname, "r" );
    	// ...
            *n = anzahl_zeichenketten;
    	return words;
    }
    

    Nerethar schrieb:

    Ist meine Speicherreservierung *Array = calloc(10, sizeof(char)*100); hierbei Richtig wenn das Array maximal 10 Zeichenketten enthalten darf und jene 100 Zeichen lang sein dürfen?

    Auch wenn du deine Variante mit der void Funktion nehmen willst/musst und mit dem dreifachen Zeiger arbeiten willst/musst, kannst du im Prinzip
    so vorgehen:

    int i, n = 10, len = 100 + 1; // Maximale Zeichenlänge 100 plus Terminator.
    	char** words = malloc ( n * sizeof ( char* ));
    	// Wenn words != NULL ....
    	if ( words )
    		for ( i = 0; i < n; i++ )
    			words[i] = malloc ( len ); // sizeof(char) ist 1, Rückgabewert von malloc auf NULL prüfen...
    	// Benutze dein Array...
    	// ...
    	// Reservierten Speicher freigeben, für jedes malloc/calloc ein free...
    	if ( words )
    		for ( i = 0; i < n; i++ )
    			free ( words[i] ); // ein free ( NULL ) wäre nicht tragisch.
    	free ( words ); // dito
    

    Dann müsstest du bloß noch die Funktionsparameter, die Zuweisung

    void read_file2( const char* fname, char*** Array, unsigned* n )
    {
    	char** words = malloc ( ...
    	// ...
    	*Array = words;
    }
    

    und den Aufruf der Funktion anpassen

    char** Array;
    unsigned n;
    read_file2 ( "test.txt", &Array, &n );
    


  • Wenn die max. Anzahl der Wörter und deren max. Länge bekannt ist, kannst du dir die dynamische Speicherverwaltung sparen und gleich ein Array von Strings definieren, wenn deine Worte keine Whitespaces enthalten können, dann kannst du auch auf fgets verzichten.

    #define MAXNUMSTR 3
    #define MAXLENSTR 100
    
    void lies(const char *datei,char a[][MAXLENSTR+1])
    {
      FILE *f=fopen(datei,"r");
      int i=0;
      while( i<MAXNUMSTR && 1==fscanf(f,"%100s",a[i++]));
      fclose(f);
    }
    
    int main(int argc,char**argv)
    {
      char strarray[MAXNUMSTR+1][MAXLENSTR+1]={0};
      int i;
      lies("bla.txt",strarray);
      for(i=0;*strarray[i];++i)
        puts(strarray[i]);
      return 0;
    }
    


  • Vielen Dank für eure Antworten,
    das ganze hat mir viel geholfen und vor allem bin ich nun auch recht gut durch meine C-Klausur gekommen heute, auch wenn es wohl dennoch nicht meine Lieblingssprache wird^^


Anmelden zum Antworten