Does array reinitializing cause memmory leaks?

Viewed 80

I found an answer on SO that suggests the following solution to reinitialize array in c.

int *foo = (int[]){1,2,3,4,5};

I am not really sure what exactly such syntax will do and I have few questions:

Will it cause memory leaks if my array was previously created?

double *my_array = (double[]){1.1, 2.2, 3.3, 4.4, 5.5};

...

my_array = (double[]){-1.1, -2.2, -3.3}; // Do i need to call free(my_array) first?

Is it allowed to use such an approach in function calls?

void foo(int *arr)
{
  arr = (int[]){-2, -7, 1, 255};
}

int main()
{
  int *my_array = (int[]){1, 2, 3};
  foo(my_array);
  
  if (my_array[2] != 1)
    return -1;
}

Generalizing:

  • Does such syntax just allocates new memory in heap with predefined values and returns pointer?
  • Does it clear automatically everything that was in the previous pointer?
2 Answers

First, the declaration int *foo makes foo a pointer, not an array.

(int[]){1,2,3,4,5} is a compound literal. It is rare there is a good reason to set pointers to compound literals in this way.

Compound literals are managed automatically, so you do not need to free them. If a compound literal appears outside any function, it has static storage duration; it exists for the entire execution of the program. Otherwise, it has automatic storage duration associated with the block it is in, and its memory reservation will end when execution of that block ends. You should not set a pointer to point to such a compound literal if the pointer is used after execution of the block ends.

In this code:

void foo(int *arr)
{
  arr = (int[]){-2, -7, 1, 255};
}

arr is set to point to the compound literal, but arr is only a function parameter. It effectively ceases to exist when the function returns.

In this code:

int *my_array = (int[]){1, 2, 3};
  foo(my_array);
  
  if (my_array[2] != 1)
    return -1;

When foo is called, its parameter arr is set to the value of my_array. When arr is changed inside foo, it does not affect my_array. my_array will still be pointing to the start of (int[]){1, 2, 3}. This would be true regardless of whether arr is set to point to a compound literal, allocated memory, or anything else: Changing a parameter inside a function does not change the thing that was passed as an argument.

To get the pointer out of the function, you could either return it or you could pass a pointer to a pointer so that the function had the address of the pointer:

void foo(int **arr)
{
    *arr = (int []) { -2, -7, 1, 255 };
}

int main(void)
{
    int *my_array = (int []) { 1, 2, 3 };
    foo(&my_array);
    …
}

However, then foo would be putting the address of its compound literal into a pointer that is used after the function ends. That is a situation where you ought to call malloc to reserve memory and then copy the data into the allocated memory. Later, after the program is done with that data, it would call free to release the memory.

This is known as compound literals and code such as int *foo = (int[]){1,2,3,4,5}; can be regarded as 100% equivalent to this:

int arr[] = {1,2,3,4,5};
int *foo = arr;

That is, a compound literal has the same scope and storage duration as a named array declared at the same scope.

Will it cause memory leaks if my array was previously created?

No. In case a compound literal was declared at local scope, it will be valid inside the { } where it was declared (so-called automatic storage duration). After that, it gets automatically cleaned up just like any other local variable. Since it isn't using allocated storage, there are no leaks.

Is it allowed to use such an approach in function calls?

No. Just like any local variable, you cannot return a pointer to it from inside a function.

Additionally, your example has a bug, it just sets the local copy of the pointer parameter arr. The pointer in the caller was passed by value and is unaffected by the arr = (int[]){-2, -7, 1, 255}; line.

Does such syntax just allocates new memory in heap with predefined values and returns pointer?

The C standard doesn't specify where variables are allocated. But when looking at all well-known compiler implementations out there, then the following will likely hold:

  • Compilers/linkers do not allocate anything on the heap unless explicitly told to through malloc.
  • Local compound literals are likely allocated on the stack and/or in registers.
  • File scope compound literals are likely allocated in the .data segment.

Does it clear automatically everything that was in the previous pointer?

Data isn't stored "inside pointers", but yes the pointed-at memory will get "cleared" (become invalid to use & available for other parts of the program) when it goes out of scope. No matter if there are pointers pointing at it or not.

Related