Home > Net >  Fill a dynamic 2D array with words of multiples text files in C
Fill a dynamic 2D array with words of multiples text files in C

Time:10-30

with this C code I want to fill a dynamic array of char with the words parsed in each differents text files returned by the readdir function.

#include <string.h>                                                             
#include <malloc.h>                                                             
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

                                            
char *getWord(FILE *fp){
    char word[100];
    int ch, i=0;

    while(EOF!=(ch=fgetc(fp)) && !isalpha(ch))
        ;//skip
    if(ch == EOF)
        return NULL;
    do{
        word[i  ] = tolower(ch);
    }while(EOF!=(ch=fgetc(fp)) && isalpha(ch));

    word[i]='\0';
    return strdup(word);
}

int readWords(const char * fn,char ** arr){
    char *word;
    FILE * fp;
    int size=0;
    //read first time to get the number of words
    fp=fopen(fn,"r");

    while(word=getWord(fp)){
        size  ;
    }

    fclose(fp);
    printf("size:%d\n",size);
    arr = (char **) malloc (size * sizeof (char *));
    //reopen to insert in dynamic array
    fp=fopen(fn,"r");
    for (int i = 0; i < size; i  ){
        arr[i] = (char *) malloc (100 * sizeof (char));
        word=getWord(fp);
        // printf("%s",word);
        strcpy(arr[i],word);
    }
    fclose(fp);

    return size;
}

int main(int narg, char *arg[] )
{
    struct dirent *de;  // Pointer for directory entry
    char absdir[256];
    char absfn[256];
    FILE * F;
    int s;

    // opendir() returns a pointer of DIR type. 
    DIR *dr = opendir(arg[1]);
    strcpy(absdir,arg[1]);
    strcat(absdir,"/");

  
    if (dr == NULL)  // opendir returns NULL if couldn't open directory
    {
        printf("Could not open current directory" );
        return 0;
    }
  

    while ((de = readdir(dr)) != NULL){
        if (de->d_type!=4){ // is file?
            strcpy(absfn,absdir);
            strcat(absfn,de->d_name);
            printf("abs_fn:%s \n",absfn);
            char** arr_words;

            s=readWords(absfn,&arr_words);

            printf("%s number of words:%d\n", absfn,s);
            for (int i=0;i<s;i  )
                printf("word %d:%s\n",i,arr_words[i]);
            
            //free 2D array

            for(int i=0;i<s;i  )
                free(arr_words[i]);
            free(arr_words);

        }
            
    }
    closedir(dr);    
    return 0;
}

the words are well parsed with getWord but i can't find the solution to fill the char **arr passed in argument and to use it latter in the main function. I want to allocated the char **arr_words dynamically with the following form

arr_words[0]=First word of file text
arr_words[1]=Second word
arr_words[s-1]=Last Word

the Readword function return the number of words read in each files.

thanks

CodePudding user response:

Your bug is a more advanced one of the problem described here: Dynamic memory access only works inside function

arr is a local variable. It's a pointer to the first pointer in an array of pointers. In order to return this to main (hang on tight now), your function need to pass a pointer to a pointer to the first pointer in an array of pointers...

Or in plain C, the dreaded three-star programming, char***. But this is actually a valid use for it, about the only valid use of three levels of indirection that exists.

Alternatively, you can just use the return for the char** and skip this extra level of indirection, which might be more readable.

Which form to use is a bit subjective, but you need to change your function to one of these:

int readWords(const char * fn, char*** arr)
{
  ... 
  *arr = malloc (size * sizeof (char *))
  ...
}

or

char** readWords(const char * fn, int* wordsRead)
{
   ...
   arr = malloc (size * sizeof (char *));
   ...
   *wordsRead = size;
   return arr;
}

CodePudding user response:

#include <string.h>                                                             
#include <malloc.h>                                                             
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

                                            
char *getWord(FILE *fp){
    char word[100];
    int ch, i=0;

    while(EOF!=(ch=fgetc(fp)) && !isalpha(ch))
        ;//skip
    if(ch == EOF)
        return NULL;
    do{
        word[i  ] = tolower(ch);
    }while(EOF!=(ch=fgetc(fp)) && isalpha(ch));

    word[i]='\0';
    return strdup(word);
}

char** readWords(const char * fn,int *wordsRead){
    char *word;
    char**arr;
    FILE * fp;
    int size=0;
    //read first time to get the number of words
    fp=fopen(fn,"r");

    while(word=getWord(fp)){
        size  ;
    }

    fclose(fp);
    printf("size:%d\n",size);
    arr = malloc (size * sizeof (char *));
    //reopen to insert in dynamic array
    fp=fopen(fn,"r");
    for (int i = 0; i < size; i  ){
        arr[i] = (char *) malloc (100 * sizeof (char));
        word=getWord(fp);
        // printf("%s",word);
        strcpy(arr[i],word);
    }
    fclose(fp);
    *wordsRead = size;

    return arr;
}



int main(int narg, char *arg[] )
{
    struct dirent *de;  // Pointer for directory entry
    char absdir[256];
    char absfn[256];
    FILE * F;
    int s;
    int wordsRead;
    char buffer[100];

    // opendir() returns a pointer of DIR type. 
    DIR *dr = opendir(arg[1]);
    strcpy(absdir,arg[1]);
    strcat(absdir,"/");

  
    if (dr == NULL)  // opendir returns NULL if couldn't open directory
    {
        printf("Could not open current directory" );
        return 0;
    }
  

    while ((de = readdir(dr)) != NULL){
        if (de->d_type!=4){ // is file?
            strcpy(absfn,absdir);
            strcat(absfn,de->d_name);
            printf("abs_fn:%s \n",absfn);
            char **arr_words;
            arr_words=readWords(absfn,&wordsRead);

            printf("%s number of words:%d\n", absfn,wordsRead);
            for (int i=0;i<wordsRead;i  ){
                
                printf("word %d:%s\n",i,arr_words[i]);
            }
            //free array of pointers

            for(int i=0;i<s;i  )
                free(arr_words[i]);
            free(arr_words);

        }
            
    }
    closedir(dr);    
    return 0;
}
  • Related