0

Let's suppose I want to write a function which take an array as argument and returns a pointer to that array. I could write it like this;

int *foo(int var[])
{
    return var;
}

Now suppose I call this function elsewhere in the code;

int a[] = {1, 2, 3};
int *pa = foo(a);

When the function foo is called, a new pointer on int is created on the stack, and that pointer is what is referred to by the name "var" inside foo. My question is; in which block is that pointer created?

If it is part of foo's block, then it will be deallocated when the function exits, so pa will point to an unallocated memory address. However, this code compiles with no warnings, while the following does;

int *foo(int var)
{
    return &var;
}

so I suppose that while int var is part of foo's block (in regard with the stack), the pointer implicitly created by int var[] is actually part of the block where foo is called. Am I right?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
magva
  • 89
  • 4

4 Answers4

1

No, you are wrong.

Both int var and int var[] are created for foo's block.

The return &var; in the 2nd example returns a pointer to local variable of foo, so it is bad.

The return var; in the 1st example returns the passed pointer, which exists outside foo, so it is fine.

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
1

If it is part of foo's block, then it will be deallocated when the function exits

Correct, the scope of var is the function foo so var will no longer exist when foo returns.

so pa will point to an unallocated memory address.

Wrong.

In C arguments and return values are "passed by value". So it's not va that you are returning. It's the value of va. So it doesn't matter that va goes out of scope.

In most expressions where an array is used, the array will be converted to a pointer to the initial element of the array (there are a few exceptions). So when you use a as a function argument, it's actually a pointer value which is passed to fooand used to initialize var. Then the same value is returned and assigned to pa. Since var is initialized with a pointer to the initial element of a, pa will also point to the initial element of a.

All your code is the same as:

int *pa = a;

Example of wrong code

To better understand the difference consider this code:

int *foo()
{
    int a[] = {1, 2, 3};
    int* var = a;
    return var;             // bad, bad, bad
}

int *pa = foo();

This code is bad. It's not because var goes out of scope but because the value of var points to a and a goes out of scope as well.

And for this code:

int *foo(int var)
{
    return &var;
}

you are absolutely correct. It's bad because you return a value which is pointing to var but var goes out of scope. Consequently, the pointer value is no longer pointing to an existing object.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
1

With C, there are no arrays when passed to functions. All the function actually gets when "passed an array", is a pointer -- an address at which it may assume there is some data, spanning some unknown length. It may assume the pointer points to a number of elements of some known type, but it would not know how many. Would you know, given a note with an address written on it, the kind and more importantly the size or number of propertie(s) at the address?

The only way such a function even knows the type of elements of the array, is because a pointer has a type -- for example, with int * var the function assumes the array is made of a number of int elements in memory, back to back.

The value of var inside foo is the same value as a, an address. That value is indeed pushed onto the stack when calling foo. Since foo returns var, because var was what it was passed, pa is assigned this value and will thus also be the same address as var and a.

The name an array is declared with may always be used as a pointer to the array, the address of the array in memory. This pointer, however, may only exist in the same sense you can say the address of your house exists -- there certainly is an address to your house which can be shared with others to locate your house, but it does not necessarily imply the actual plate on the side of your house. That's storing the address. With an expression like pa = foo(...), pa is such a pointer, there is actually allocated (for as long as pa needs to live, as defined by scoping rules) space in memory to hold an address, and the value of the pointer is stored there.

Your array is stored in memory and foo, for instance, knows where, because it is passed the address of the array, although it must assume the span of the array (its length). The type of the pointer is how foo knows how the array is partitioned into elements.

Consequently, with return &var, as shown in your second variant of foo, the address of the value storing the address of the array defined with a, is returned. Put another way, you are returning the address of where an address is stored. The analogy with your house would be you telling your friend where to find a note with the address of your house written on it, i.e. the address (location) of the note with an address of the house written on it.

See also Why do arrays in C decay to pointers?

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95
1

C does not really have function parameters of type "array of T" (for some type T) because the compiler "adjusts" their type to "pointer to T".

OP's foo function definition is equivalent to the following:

int *foo(int *var)
{
    return var;
}

The function merely returns the pointer that was passed to it. For the function call elsewhere in the code:

int a[] = {1, 2, 3};
int *pa = foo(a);

Function foo is called with a pointer to a[0] and returns the same pointer value and so the same pointer value is assigned to pa. Thence, pa points to a[0].

Ian Abbott
  • 15,083
  • 19
  • 33