2

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?
OKEE
  • 450
  • 3
  • 15
  • In your second snippet, the `foo` function just changes a copy of the pointer that is passed as its argument and has no effect on the value in `main`. You *could* make the argument an `int **arr` but, then, you are returning a pointer to local data and will have undefined behaviour. – Adrian Mole Jul 05 '21 at 10:00
  • @Adrian Mole, maybe you are right, but compiling and running the program it is changing the original array. – OKEE Jul 05 '21 at 10:02
  • When I run the code in your last snippet, the value of `my_array[2]` remains as `3` (as I would expect). – Adrian Mole Jul 05 '21 at 10:04
  • Sorry, my bad, I oversimplified the example, like that it is changing the original one. – OKEE Jul 05 '21 at 10:11
  • Your edit (made after an answer was posted) has made that answer appear invalid. You should consider rolling back that edit. (Well, it seems that the answer was being composed while you made your edit ... still, maybe rollback anyway: it's a good answer and explains the basic problem with your approach.) – Adrian Mole Jul 05 '21 at 10:15

2 Answers2

5

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.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • "putting the address of the compound literal into a pointer that is used after the function ends." deserves clarity: which of the 2 literals, which of the 2 functions? IAC, it is OK in the last snippet unless after `foo()`, `my_array` is read. – chux - Reinstate Monica Jul 05 '21 at 10:26
1

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396