Search code examples
arrayscfilememory-managementstructure

C: Memory allocation issues


I'm having an issue with (I think) memory reallocation in C. The program is meant to run such that when fopen(array, &num); is called, it will first retrieve the number of elements in the array from file and place that in num, reallocate memory for the array pointer given to give it enough room to store the contents of the file proper, then copy the values over into that array. This seems to work while still in the fopen function (shown by 'mark 1'), but does not work outside of this (shown by 'mark 2') instead seeming to spew out random memory garbage. Any help appreciated (both with code and formatting my poorly laid out question).

//main.c
void Rtest(){

  char num;
  struct individual *array;
  array = (struct individual *) malloc(sizeof(struct individual));

  openf(array, &num);

  printf("%d\n", num);

  for (int i = 0; i < num; i++) {printf("%s\n", array[i].name);} //mark 2

  free(array);

}
//fil.h
struct individual {
    char name[32];
    char stats[7];
    char role;
    char roles[13];
};

void openf(struct individual *array, char *num){

  FILE *fp;

  fp = fopen("save.bin", "rb");
  fread(num, 1, sizeof(char), fp);
  array = (struct individual *)realloc(array, *num * sizeof(struct individual));
  printf("%d\n", sizeof(*array));
  fread(array, *num, sizeof(struct individual), fp);
  for (int i = 0; i < *num; i++) {printf("%s\n", array[i].name);} //mark 1

  fclose(fp);

}

File contents:

03 43 61 72 6C 73 6F 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 03 04 05 06 08 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 43 61 72 6C 73 6F 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 03 04 05 06 08 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 43 61 72 6C 73 6F 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 03 04 05 06 08 00 01 02 03 04 05 06 07 08 09 0A 0B 0C


Solution

  • When you want to change the argument inside a function, you pass a pointer to it. For example, inside Rtest you declared a char called num. It has no value, and you sent it to openf, But you actually sent the pointer to num since you wanted to change its value, you did it correctly and indeed openf changed num value successfully.

    But how about array? Well, you declared it on Rtest and allocated space in memory for it, which is all correct. Then, you wanted to send it to Rtest as a pointer so the function could change it. array is a variable of the type "pointer to struct individual". This is okay, but if you wanted to change it inside Rtest, well you need to send a pointer for that variables.. hence, you needed a "POINTER TO pointer to struct individual". Note that the variable name was copied from before and I just added "POINTER TO"

    I'm sure you know what pointer to pointer is, and what you needed to do is use:

    openf(&array, &num);
    

    And of course modift openf as well so it will use the new "pointer to pointer", something like that:

    void openf(struct individual **array, char *num){
    
      FILE *fp;
    
      fp = fopen("save.bin", "rb");
      fread(num, 1, sizeof(char), fp);
      *array = (struct individual **)realloc(*array, *num * sizeof(struct individual));
      printf("%d\n", sizeof(**array));
      fread(*array, *num, sizeof(struct individual), fp);
      for (int i = 0; i < *num; i++) {printf("%s\n", (*array)[i].name);} //mark 1
    
      fclose(fp);
    
    }
    

    When I run this code on my machine, along with Rtest and provided save.bin I get the following output:

    53
    Carlson
    Carlson
    Carlson
    3
    Carlson
    Carlson
    Carlson
    

    EDIT: As @WhozCraig mentioned in the comments, You could use the unused return value for the function and return the pointer for the "new" array, which might be a slightly better way of doing things here instead of the "pointer to pointer" stuff, but its up to you.