Reputation: 59
Most websites say something like this:
C programming does not allow to return an entire array as an argument to a function. However, you can return a pointer to an array by specifying the array's name without an index.
I've just begun with pointers and as far as I understand, a pointer variable is a variable which stores a memory address. When we dereference it using *, we get to that memory address and hold the value stored there. Also, in the case of an array, the pointer must point to the first element.
Now, if our function returns a pointer to the first element of our array as in this example:
int * myFunction() {
.
.
.
}
In that case,
Second point to remember is that C does not advocate to return the address of a local variable to outside of the function, so you would have to define the local variable as static variable.
In computer programming, a static variable is a variable that has been allocated statically so that its lifetime or "extent" extends across the entire run of the program.
Another website says,
The static storage class instructs the compiler to keep a local variable in existence during the life-time of the program instead of creating and destroying it each time it comes into and goes out of scope.
Someone please give me a clear and basic explanation what a static variable really is and how it is relevant in this context(returning array from function).
I'm really confused.
Upvotes: 1
Views: 12734
Reputation: 123458
Going back to front:
What exactly is a static variable?
An object with static
storage duration has storage allocated for it when the program first starts up, and that storage is held until the program exits. An object has static
storage duration if:
static
keywordExample:
#include <stdio.h>
int g_var; // static storage duration
void foo( void )
{
static int s_var = 10; // static storage duration
int l_var = 10; // auto storage duration
printf( "g_var = %d, s_var = %d, l_var = %d\n", g_var++, s_var++, l_var );
}
In this snippet, both g_var
and s_var
have static
storage duration; g_var
because it was declared at file scope, s_var
because it was declared with the static
keyword. By virtue of having static
storage duration, g_var
is implicitly initialized to 0. Note that s_var
is initialized once at program startup - it will not be re-initialized to 10
on subsequent calls to foo
. Thus, each time you call foo
, the output will be
g_var = 0, s_var = 10, l_var = 10
g_var = 1, s_var = 11, l_var = 10
g_var = 2, s_var = 12, l_var = 10
...
l_var
has auto
storage duration - its lifetime is limited to the lifetime of the foo
function. Each time foo
is called, storage for a new instance of l_var
is allocated and initialized at function entry and released when the function exits. This is important - l_var
ceases to exist when foo
exits, so any pointer to it will become invalid when foo
returns1.
This is why you can't do something like
int * bar( void )
{
int array[N];
...
return array;
}
because array
ceases to exist once bar
exits, and the pointer that gets returned is invalid.
Now, one way around this is to declare the array as static
:
int * bar( void )
{
static int array[N];
...
return array;
}
In this case, array
doesn't go away when the function exits, so the pointer is still valid.
However...
This creates other problems. Only a single instance of array
is ever created, and it contains the last thing written to it by another call to bar
. The code is no longer re-entrant; it can't safely be interrupted in mid-execution, then called by another function before the first invocation has completed. Creating a static
array just so you can cleanly return a pointer to it is usually the wrong answer.
Either pass a target array as an argument to the function:
void foo( int *array, size_t arraySize )
{
...
array[i] = some_value;
...
}
or dynamically allocate an array and return the pointer to it:
int * bar( void )
{
int *array = malloc( sizeof *array * N );
if ( array )
{
// initialize array contents
}
return array;
}
The problem with this is that someone else is responsible for releasing that memory when you're done.
Does "the function returning a pointer" mean it is returning the memory address to which the pointer points?
The function returns the value of a pointer, which is the address of another object. In the code above, bar
returns the value of the expression array
, which turns out the be the address of the first element of array
.
In the second case of bar
above, the value being returned is equivalent to &array[0]
.
What and how are we going to dereference it?
You can dereference a pointer in two ways - using the *
dereference operator, or using the []
subscript operator.
The subscript operation a[i]
is defined as *(a + i)
- given the address a
, offset i
elements (not bytes) from a
and dereference the result. So you can take the pointer returned from bar
and do the following with it:
int *p = bar();
printf( "p[0] = %d\n", *p );
printf( "p[0] = %d\n", *(p + 0) );
printf( "p[0] = %d\n", p[0] );
So, does this mean arrays and pointers are the same thing? No. Arrays are not pointers; however, under most circumstances, an array expression (i.e., an expression of type "N-element array of T
") will be converted ("decay") to a pointer expression ("pointer to T
").
l_var
occupied still exists, so the value of the pointer doesn't suddenly become garbage or anything like that; however, that memory location is now available for something else to use, and if you try to read or write to that location you can cause problems.
Upvotes: 1
Reputation: 2514
Question 3:
int a;
void foo() {
int b
static int c;
}
int main() {
foo();
}
When the program starts, the memory for a and c are allocated and remain allocated until the program exits. So there is exactly on a and on c at any given time. Each time anyone (here main) calls foo, b is allocated on the stack until that function returns.
About the Quote in front of question 3:
Returning the address of a and c is no problem, because those exist as long as the program lasts, but returning an address to b is an error because as soon as the caller gets the pointer in his hand, the pointer points to invalid memory.
Question 1:
You dereference a pointer by putting an asterisk in front. It doesn't matter, that that pointer points to. It it is an array, you can increment or decrement the pointer to get to the index you're trying to reach like in a simple addition: *(p + 4) will access the 5th element (because *(p + 0) is the first one, so *(p + 1) is the second one and so on).
Instead of writing *(p + 4) you can also write p[4].
So assuming you function looks like this:
int * myFunction() {
static int array[8];
return array;
}
then the return statement will return the address of the array which is the exact same thing as the address of the first element of the array.
so, having int * p = myFunction(); you can then access the array with the intuitive syntax p[0] = 42; ...; p[7] = 23;
Question 2:
A function, that returns a pointer is a function that returns a pointer. A pointer is a thing, which points to a point in memory. Usually that is called a memory address, but the C language doesn't care. So, in practice, "the function returning a pointer" means it is returning the memory address to which the pointer points, yes.
Upvotes: 0
Reputation: 36463
What and how are we going to dereference it?
The pointer variable returned by the function.
By using the appropriate operator *
, an example:
int z = 5;
int* pointer_to_z = &z; // get memory address of z and store that in pointer_to_z
int can_i_have_my_z_back_please = *z; // check what value is at that memory address and store it, a copy is made here.
Does "the function returning a pointer" mean it is returning the memory address to which the pointer points?
It's returning a pointer variable, this variable holds the memory address of the value. Basically, "pointing to " a value is the same as "having it's address".
What exactly is a static variable? [I surfed enough but didn't find anything statisfying].
There's lots of good SO answers on what a static variable is already. To summarize (only going in on the lifetime of the variable and not it's linkage) a static variable is valid for the rest of the program once initialized, this means that it's lifetime is not scope bound like a local variable is:
void hello()
{
int x = 5;
} // x destroyed here..
void hello_static()
{
static int x = 5;
} // x will only be destroyed at the "end" of the program
This in turn means that it's completely safe to return a pointer (the memory address) of a local static variable since the static variable will still be accessible :
int* return_my_static()
{
static int a = 5;
return &a;
}
int main()
{
int* pointer_to_static = return_my_static(); // get the memory address of the static
printf("%i", *pointer_to_static); // print out the value by dereferencing
}
But, doing so for a local non-static variable will cause undefined behaviour as the variable pointed to (it's memory address) is no longer valid as it has been destroyed:
int* return_local()
{
int a = 5;
return &a;
} // a is destroyed here.. oopsies
int main()
{
int* pointer_to_local = return_local(); // get the memory address of the local.
//local variable has been destroyed now and 'pointer_to_static' now points to garbage memory!
printf("%i", *pointer_to_local); // Try to print out the value by dereferencing, this is undefined behaviour, anything can happen.
}
Note that the above code might run and output the expected result but that is sheer luck, this is undefined behaviour and should be avoided at all costs since anything can happen at this point.
Upvotes: 2