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.

5
  • 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; Commented Sep 18, 2022 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. Commented Sep 18, 2022 at 19:38
  • If you have syntax issues the compiler will tell you and you will not be able to run your program. Commented Sep 18, 2022 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? Commented Sep 18, 2022 at 19:42
  • Please see my recent answer: Creation of Dynamic Array of Strings in C. 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. Commented Sep 18, 2022 at 19:48

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

3 Comments

And how could this be solved, so that auxiliary remains pointed to said value regardless if the function finished its execution?
@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?
yes because it can be int, array of strings, bool, etc.
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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.