In the code
char *fun()
{
char *p = "ram";
return p; //char* is local, even though in main it gets printed. why?
}
The variable p
is local to the function, and its lifetime ends with the function. However, you are returning p
's value, not its address, so that doesn't really matter here.
p
's value is the address of the string literal "ram"
. String literals are stored in such a way that they are available over the lifetime of the entire program, from startup to termination - the literal "ram"
does not cease to exist when fun
exits, so its address stays valid.
And why below does not work? when i changed from char *p = "ram" to char p[]="ram" ?
Now you've changed how and where the string gets stored. Instead of p
being a pointer that stores the address of the string literal, it is now an array that stores the contents of the string itself. The lifetime of the string is now the same as the lifetime of the function, so once the function exits, the array that stored that string no longer exists and the return value is not valid.
I took your code and added a utility1 to display the address and contents of various items in memory. First we start with the first version where p
is a pointer:
#include <stdio.h>
#include "dumper.h"
char *fun( void )
{
char *p = "ram";
char *names[] = { "p", "\"ram\"" };
void *addrs[] = { &p, "ram" };
size_t sizes[] = { sizeof p, sizeof "ram" };
puts( "In fun: ");
dumper( names, addrs, sizes, 2, stdout );
return p;
}
int main( void )
{
char *x;
char *names[] = { "x", "\"ram\"" };
void *addrs[] = { &x, "ram" };
size_t sizes[] = { sizeof x, sizeof "ram" };
puts( "Before call to fun:" );
dumper( names, addrs, sizes, 2, stdout );
x = fun();
puts( "After call to fun:" );
dumper( names, addrs, sizes, 2, stdout );
return 0;
}
And here's the output:
Before call to fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee2451a40 a0 1a 45 e2 ..E.
0x7ffee2451a44 fe 7f 00 00 ....
"ram" 0x10d7aef04 72 61 6d 00 ram.
In fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
p 0x7ffee24519b8 04 ef 7a 0d ..z.
0x7ffee24519bc 01 00 00 00 ....
"ram" 0x10d7aef04 72 61 6d 00 ram.
After call to fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee2451a40 04 ef 7a 0d ..z.
0x7ffee2451a44 01 00 00 00 ....
"ram" 0x10d7aef04 72 61 6d 00 ram.
First, notice that the string literal "ram"
has the same address in both fun
and main
. Again, string literals are allocated such that they are available over the lifetime of the program. You'll notice its address is much lower than the other items, indicating it's in a very different region of memory.
Again, notice that p
only stores the address of the string, not its contents. So even though p
ceases to exist, its value continues to be valid.
Now, we change that code so that p
is an array, not a pointer:
#include <stdio.h>
#include "dumper.h"
char *fun( void )
{
char p[] = "ram";
char *names[] = { "p", "\"ram\"" };
void *addrs[] = { &p, "ram" };
size_t sizes[] = { sizeof p, sizeof "ram" };
puts( "In fun: ");
dumper( names, addrs, sizes, 2, stdout );
return p;
}
int main( void )
{
char *x;
char *names[] = { "x", "\"ram\"" };
void *addrs[] = { &x, "ram" };
size_t sizes[] = { sizeof x, sizeof "ram" };
puts( "Before call to fun:" );
dumper( names, addrs, sizes, 2, stdout );
x = fun();
puts( "After call to fun:" );
dumper( names, addrs, sizes, 2, stdout );
return 0;
}
Now our output looks like this:
Before call to fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee059ea40 98 ea 59 e0 ..Y.
0x7ffee059ea44 fe 7f 00 00 ....
"ram" 0x10f661efc 72 61 6d 00 ram.
In fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
p 0x7ffee059e9bc 72 61 6d 00 ram.
"ram" 0x10f661efc 72 61 6d 00 ram.
After call to fun:
Item Address 00 01 02 03
---- ------- -- -- -- --
x 0x7ffee059ea40 bc e9 59 e0 ..Y.
0x7ffee059ea44 fe 7f 00 00 ....
"ram" 0x10f661efc 72 61 6d 00 ram.
Instead of storing the address of the string literal, p
now stores the contents of the string itself. Once fun
exits, p
(and by extension the string it contains) ceases to exist.
- Available here