0

I have a problem using dynamic memory in C. I am creating a struct whose data is a number and a pointer to another struct (in short, an array of struct). The goal is for the parent struct to store an array of another struct using dynamic memory.

The problem I have is to access the cells of the created array, because I don't know if it's due to syntax issues (I'm new to C), or that I'm creating the array wrong, I can't modify the information contained in each cell of the contained array inside the parent struct. I can only modify by default the first cell.

This is my code, any idea or suggestion will be appreciated.

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

typedef struct {
    char string[64];
    void* date;
    void* colour;
} DataState;

typedef struct {
    int number;
    DataState* array;
} Book;

Book* makeBook (int number){
    int a=5;
    void* auxiliary=&a;
    Book* book_A=(Book*)(malloc(sizeof(Book)));
    book_A->number=number;
    book_A->array=(DataState*)(malloc(number*sizeof(DataState))); //creating array of structs inside main struct.
    //And what I want to do is something like this, modify the information contained in cells of the array of structs of the main struct.
    book_A->array[3]->date=auxiliary;
    return book_A;
}

From already thank you very much.

Juan598
  • 29
  • 3
  • Post your error message(s) (as text, please, not as an image). One problem: `book_A->array[3]` is a structure, not a pointer because the `[3]` dereferences the `array` pointer to access the fourth `struct` in the array. So instead of `book_A->array[3]->date=auxiliary;`, it should be `book_A->array[3].date=auxiliary;` – Andrew Henle Sep 18 '22 at 19:27
  • 1
    `a` only exists in `makeBook`, it disappears when `makeBook` returns, so the address of where it used to live (`auxiliary` and `->date`) is no longer valid. – yano Sep 18 '22 at 19:38
  • If you have syntax issues the compiler will tell you and you will not be able to run your program. – Gerhardh Sep 18 '22 at 19:39
  • so yano,would you recommend me to make a malloc so that when the function finishes, that pointer is saved? Well, as I understand it, once the execution of the function is finished, it is deleted from the activation register? – Juan598 Sep 18 '22 at 19:42
  • Please see my recent answer: [Creation of Dynamic Array of Strings in C](https://stackoverflow.com/a/73737192/5382650). It is very similar to what you're doing. That OP just wanted strings, but [ironically] I gave an example that used an array of book structs. – Craig Estey Sep 18 '22 at 19:48

2 Answers2

0

Here:

book_A->array[3]->date=auxiliary;

you assign a value of auxiliary to the 3rd element of an array, but auxiliary is defined as

void* auxiliary=&a;

while a is an automatic variable in your function.

Automatic variables disappear at the return from the function, hence the pointer assigned to book_A->array[3]->date becomes invalid as soon as the return is executed.

CiaPan
  • 9,381
  • 2
  • 21
  • 35
  • And how could this be solved, so that auxiliary remains pointed to said value regardless if the function finished its execution? – Juan598 Sep 18 '22 at 19:48
  • @Juan598 you need to `malloc` space for `a` as you have for other things in the function: `int* a = malloc(sizeof *a); ... ->date=a`. But really, I'd consider a re-architecture. Does `date` even need to be a `void` pointer? – yano Sep 18 '22 at 20:19
  • yes because it can be int, array of strings, bool, etc. – Juan598 Sep 18 '22 at 20:42
0

If you want the data saved in a to remain valid after makeBook returns, then you must allocate it in more persistent storage than automatic. You've essentially done this:

int* foo()
{
  int a = 5;
  // WRONG, cannot return the address of a local variable
  return &a;
}

int main(void)
{
  int* a_addr = foo();
  // WRONG, invokes undefined behavior
  printf("a = %d\n", *a_addr);
}

If you want a to persist outside of foo, a possible option is:

int* foo()
{
  int* a = malloc(sizeof *a);
  // always check the return value of malloc
  if (a != NULL)
  {
    *a = 5;
  }
  // this is ok. `a` is still in automatic storage, but this _returns_ its
  // value, which is a pointer to data _not_ in automatic storage.
  return a;
}

int main(void)
{
  int* a_addr = foo();
  // still must check here, malloc in `foo` could have failed. Probably
  // better to design an architecture where you only check validity once
  if (a_addr != NULL)
  {
    printf("a = %d\n", *a_addr);  // prints a = 5
    // don't forget to `free(a_addr)` when you're done with it, or you can
    // let the OS clean up the memory when the process exits.
  }
  else
  {
    // handle error how you want
    fprintf(stderr, "Out of mem!\n");
  }
  return 0;
}
yano
  • 4,827
  • 2
  • 23
  • 35