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;
}