Search code examples
arrayscstringrealloc

Passing an array of strings as argument and modifying it dynamically within the function in C


I need to dynamically populate an array of strings in C. Here is the example of my code. Compiles fine, segmentation faults. Is it possible to achieve this functionality?

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

#define MAX_FILE_NAME_LENGTH 255

void loadList(char*** files,int *filesSize);

int main (int argc, char *argv[])
{
  char** files;
  int filesSize=-1;

  loadList(&files, &filesSize);
  //printf("filesize= %d\n",filesSize );
  for(int i=0;i< filesSize;i++) printf("%s\n", files[i]);
  free(files);

  return 0;
}

////////////////////////////////////////////////////////////////////////////////

void loadList(char*** files,int *filesSize){
 *filesSize=3;
 //some arry for the example
 char *values[] = {"100.dat", "150.dat", "200.dat"};
 for(int i=0;i< *filesSize;i++){
   *files=(char**) realloc(*files,(i+1) * sizeof(**files));
   *files[i]=malloc((MAX_FILE_NAME_LENGTH+1) * sizeof(char*));
   strcpy(*files[i],values[i]);
   printf("%s\n", files[i]);
 }
}



Solution

  • In *files = (char **)realloc(*files, (i + 1) * sizeof(**files)); you rely on *files to point at already allocated memory or NULL. Neither is true.

    *files[i] should also be (*files)[i] because of operator precedence.

    You also forgot to free the allocations made inside the loop. A fix could look like this:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAX_FILE_NAME_LENGTH 255
    
    void loadList(char ***files, size_t *filesSize) {
        // some array for the example
        const char *values[] = {"100.dat", "150.dat", "200.dat"};
        *filesSize = sizeof values / sizeof *values;
    
        *files = NULL; // crucial for first realloc
    
        for (int i = 0; i < *filesSize; i++) {
            *files = realloc(*files, (i+1) * sizeof **files);
            // I'm using strlen here instead of MAX_FILE_NAME_LENGTH but
            // you can change that back if you want more space than the
            // strings really need.
            (*files)[i] = malloc((strlen(values[i]) + 1) * sizeof(char));
            strcpy((*files)[i], values[i]);
        }
    }
    
    int main(int argc, char *argv[]) {
        char **files;
        size_t filesSize = -1;
    
        loadList(&files, &filesSize);
        // printf("filesize= %d\n",filesSize );
        for (int i = 0; i < filesSize; i++) printf("%s\n", files[i]);
    
        // free what was allocated in the loop
        for (int i = 0; i < filesSize; i++) free(files[i]);
        free(files);
    
        return 0;
    }
    

    One note on files = realloc(*files, ... though: If realloc fails you've lost the original pointer and will not be able to recover. Either assign the return value to a temporary variable and check that it worked or return from the function (after setting *filesSize to i) or exit the program if *files == NULL.