Search code examples
cfgetsstrcmp

Load Text File Into 2D Array Then Compare Against Literal


I have 2D array I want populate then compare to literal

below is compare code, i try different things with no success

char** list;

load(list);

if(strcmp(list[0], "aasdf"))
{
    printf("win\n");
}

the above segfaults on strcmp

load function

void load(char **list)
{
int MAX_NUM_LINES = 1000;

FILE *fp;

list = malloc(MAX_NUM_LINES*sizeof(char*));
fp = fopen("list", "r");

line_ct = 0;
char line[256];
while ( fgets(line, 256, fp) != NULL )
{
   int len = strlen(line);
   list[line_ct] = malloc(len * sizeof(char));
   strcpy(list[line_ct], line);
   line_ct++;

   if(line_ct == MAX_NUM_LINES)
   {
        break;
   }
}

fclose(fp);
}

any ideas on why is segfault?

also i try before strcmp

printf("Line: %s\n", *list[0]);

it segfault to


Solution

  • when you come back from load the var list is not set, so when you do

     if(strcmp(list[0], "aasdf"))
    

    you have an undefined behavior using list (typically a crash)


    The first solution is use an output var

    you need to change

    load(list);
    

    by

    load(&list);
    

    and you need to change the type of list and dereference it in load, so :

    void load(char ***list)
    {
      *list = malloc(MAX_NUM_LINES*sizeof(char*));
      ...
      (*list)[line_ct] = malloc((len + 1) * sizeof(char));
      strcpy((*list)[line_ct], line);
    

    I also added 1 to len to have place for the ending null character.

    (edit) The use of a *** is not very common, as suggested by @user3629249 in a remark you can look at Triple pointers in C: is it a matter of style? reading carefully the answers.


    The second solution is to return the allocated array :

    char** list = load();
    

    with

    char ** load()
    {
       char **list;
       ...
       return list;
    

    also adding 1 to len when you allocate each line


    Out of that if you read more than MAX_NUM_LINES lines you write out of the array again with an undefined behavior, and the caller of load does not know how much lines you read.

    To avoid that you can first initialize list with malloc(0) then use realloc to increase the size of list each time you read a line, that allows to allocate the right size. To indicate the size to the caller you can use an additional output var or to allocate one entry more to place NULL in the last entry (all depends on how you use the read array in the code calling load)