2

I have been searching for a solution for this for a while now. I think I know what is happening and what the solution should be, however I am not quite sure how to implement it.

I have a struct that contains two variable length arrays. These are to be filled within a function and returned to the calling function to do work with. The problem seems to be that any assignment of the variable length array becomes invalid when the called function goes out of scope. I would guess that a solution may be to allocate the memory on the heap and then free the memory once I am done with the struct in the calling function. A code example is given below

struct fields {
  int n;
  double * A;
  double * B;
};

struct fields field() {
  int n = 4;
  double A[n] = { 1, 2, 3, 4 };
  double B[n] = { 1, 2, 3, 4 };

  struct fields field;
  field.n = n;
  field.A = A;
  field.B = B;
  /* field can be accessed with n, A, B set properly */
  return field;
}

double calling_function() {
  struct fields field1 = field();
  /* field1 contains n but A and B have not returned */
  .
  .
  .
}
trincot
  • 317,000
  • 35
  • 244
  • 286
Planck
  • 33
  • 2
  • `I would guess that a solution may be to allocate the memory on the heap and then free the memory once I am done with the struct in the calling function.` -- That would be a good guess. – Robert Harvey May 11 '21 at 14:01
  • Nitpicking, but you don't have a structure with variable-length arrays (those aren't really possible), but you have a structure with *pointers* And those pointers must point to something whose life-time will be longer than the structures themselves (or any copies of the structures). – Some programmer dude May 11 '21 at 14:03
  • 1
    What you're doing is basically returning pointers to local variables, and that has never been allowed. Local (non-static) variables have a life-time until their scope ends. In the case of the arrays `A` and `B`, that's when the function returns. See e.g. [How to access a local variable from a different function using pointers?](https://stackoverflow.com/questions/4570366/how-to-access-a-local-variable-from-a-different-function-using-pointers) for one earlier question on the subject. – Some programmer dude May 11 '21 at 14:05

2 Answers2

1

First, you don't actually have two variable length arrays in your struct. It would be an error if you did. What you actually have is two pointers, each of which may point to the first element of an array of any size.

The problem you're having is that you're taking arrays created as local variables in the field function and assigning them (or more accurately pointers to their first elements) to the struct which is being returned. This means you're returning the address of local variables from the function. The lifetime of these locals end when the function exits, so the memory those pointers points to is invalid (and in fact the pointer values themselves are indeterminate) and attempting to dereference those pointers triggers undefined behavior.

Also note that a variable length array cannot be initialized.

You need to dynamically allocate space for the A and B fields and write to those arrays. You can however use the existing local arrays to perform a memcpy if you don't want to copy individual members.

struct fields field() {
  double A[4] = { 1, 2, 3, 4 };
  double B[4] = { 1, 2, 3, 4 };

  struct fields field;
  field.n = 4;
  field.A = malloc(sizeof A);
  field.B = malloc(sizeof B);
  memcpy(field.A, A, sizeof A);
  memcpy(field.B, B, sizeof B);
  return field;
}
dbush
  • 205,898
  • 23
  • 218
  • 273
  • Thanks for all the comments and the two solutions, dbush's version did the trick! Without having to rejig the rest of the code to deal with the pointer instance of fields. Many thanks, this saved me a lot of time. – Planck May 11 '21 at 14:36
0

local variables has their life-time - only inside the stack frame of their function.

if you want to create a variable and then use it outside the function you need to declare a variable with "bigger" scope like dynamically allocate it on the heap.

the life-time of heap variable is from the memory request (malloc) until 'free' or end of program.

so, if you want to return this struct it should be like this:

struct fields *field() {


    struct fields *field = (struct fields *)malloc(sizeof(struct fields));
    if (NUUL == filed)
    {
        return (NULL);
    }

    field->n = 4;

    field->A = (double *)malloc(sizeof(double) * n);
    //check if malloc fail

    field->B = (double *)malloc(sizeof(double) * n);
    //check if malloc fail

    //assign A and B their values

      return (field);
    }

**don't forget to free this allocation

free(field->A);
free(field->B);
free(field);
Asaf Itach
  • 300
  • 6
  • 13