on returning a ptr in a local stack

S

student1976

All
Beginner/Intermediate level question. I understand that returning
ptr to local stack vars is bad.

Is returning foo_p_B from fnB() reliable all the time, so that using
foo_p_A does not break?

Thanks
Josh

fnA()
{
struct foo* foo_p_A;
int a=1, b=2;

foo_p_A = fnB( a, b);

/* Will this work all the time? */
foo_p_A->xxx
}

struct foo*
fnB( int a, int b)
{
struct foo* foo_p_B;

foo_p_B = fnC(a,b);

return foo_p_B;
}

struct foo*
fnC(int c, int d)
{
struct foo* foo_p_C;
....
foo_p_C = (struct foo*) malloc(...);
...
return foo_p_C;
}
 
B

Ben Pfaff

Is returning foo_p_B from fnB() reliable all the time, so that using
foo_p_A does not break?

Yes: it is a pointer to an object with allocated lifetime (unless
the call to malloc returns null). A pointer into allocated
storage remains valid until the storage is freed.
 
D

Dave Vandervies

All
Beginner/Intermediate level question. I understand that returning
ptr to local stack vars is bad.

Yes. The reason for that is that the local variable goes away when the
function returns, so you're left with a pointer that no longer points
at anything.

(Note also that the "stack" you refer to need not look anything like
what you probably think it looks like[1].)

Is returning foo_p_B from fnB() reliable all the time, so that using
foo_p_A does not break?

[Code kept below for reference]

Yes, assuming that it's not NULL (which you don't seem to be checking
for). The pointer that fnB returns originally came from malloc, and
anything you get from malloc will exist until you free it.

The thing to remember here is that a pointer is a /value/ that tells
you where to find an /object/. As long as it's pointing at something
that still exists (that is, the the pointer value refers to an object
that hasn't disappeared), you can pass that value up, down, or sideways
through the call stack with wild abandon, and you can use it to access
the object it refers to anywhere; but when the object it refers to stops
existing (for example, when the function invocation that created a local
variable returns, or when the memory obtained from malloc() is given to
free()), you can't use the pointer value anymore either.

(Note that the more different places you've put any particular pointer
value, the harder it is to make sure that all of those places know when
the object it's pointing at stops existing, so in general it's a good
idea to abandon abandon and pass pointer values around with great care.)


As a side note, your malloc call looks like this:
foo_p_C = (struct foo*) malloc(...);

(and there's a good chance that the "..." part includes "sizeof(struct
foo)" somewhere).

It would be a good idea to get in the habit of writing your mallocs
like this instead:
foo_p_C = malloc(nelems * sizeof *foo_p_C);

The void * that malloc returns will be converted to the appropriate type
by the compiler (if it complains, that means either you haven't told the
compiler what type malloc returns and you should #include <stdlib.h>
or you're using a C++ compiler and you should be using new instead of
malloc), and using "sizeof *pointer_on_left_side_of_assignment" saves
you the trouble of looking up which type it is (and saves you the trouble
of changing all your mallocs if you change the type).


fnA()
{
struct foo* foo_p_A;
int a=1, b=2;

foo_p_A = fnB( a, b);

/* Will this work all the time? */
foo_p_A->xxx
}

struct foo*
fnB( int a, int b)
{
struct foo* foo_p_B;

foo_p_B = fnC(a,b);

return foo_p_B;
}

struct foo*
fnC(int c, int d)
{
struct foo* foo_p_C;
....
foo_p_C = (struct foo*) malloc(...);
...
return foo_p_C;
}


dave

[1] All that's actually required of it is that it can store and manage
function invocation records in a stack-like fashion. Your
implementation probably uses a contiguous block of memory that it
indexes with a register to keep track of where it is, but there have
been real implementations that have done it in heap-allocated blocks,
and there's nothing other than common sense and lack of creativity
that prevents an implementation from putting them in a cave somewhere
in Antarctica.

--
Dave Vandervies (e-mail address removed)
I'd abandon abandon if I were you, and jump from record to record with
extreme care. --Richard Heathfield and Bill
The requirements call for abandon, so abandon it has to be. Godfrey in CLC
 
R

Rg

You seem to be misunderstanding two different concepts...

Very briefly:

- It's bad, evil, awful to return the *address* of an object locally
declared, unless this object is *static*.

- It's OK to keep an address of a non-local object in a local pointer
and return this address to a callee function.

Amike,
rg
 
S

student1976

Thank you all for the comments...was really helpful.

Just fyi...the code below malloc does check for null

Thanks
Josh.
 
F

Fred Kleinschmidt

All
Beginner/Intermediate level question. I understand that returning
ptr to local stack vars is bad.

Is returning foo_p_B from fnB() reliable all the time, so that using
foo_p_A does not break?

Thanks
Josh

fnA()
{
struct foo* foo_p_A;
int a=1, b=2;

foo_p_A = fnB( a, b);

/* Will this work all the time? */
foo_p_A->xxx

Yes. But you need to free foo_p_A before returning from fnA
or you will have a memory leak.
}

struct foo*
fnB( int a, int b)
{
struct foo* foo_p_B;

foo_p_B = fnC(a,b);

foo_p_B now points to malloc'd memory - not local memory.
No problem returning it to the caller.
return foo_p_B;
}

struct foo*
fnC(int c, int d)
{
struct foo* foo_p_C;
....
foo_p_C = (struct foo*) malloc(...);

Do not cast malloc. It will hide the fact that you neglected
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,252
Latest member
MeredithPl

Latest Threads

Top