By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,243 Members | 1,141 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,243 IT Pros & Developers. It's quick & easy.

on returning a ptr in a local stack

P: n/a
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;
}

Dec 19 '06 #1
Share this Question
Share on Google+
6 Replies


P: n/a
st*********@gmail.com writes:
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.
--
"It would be a much better example of undefined behavior
if the behavior were undefined."
--Michael Rubenstein
Dec 19 '06 #2

P: n/a
In article <11*********************@t46g2000cwa.googlegroups. com>,
<st*********@gmail.comwrote:
>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 dj******@csclub.uwaterloo.ca
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
Dec 19 '06 #3

P: n/a
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
st*********@gmail.com wrote:
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;
}
Dec 19 '06 #4

P: n/a
Thank you all for the comments...was really helpful.

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

Thanks
Josh.

On Dec 19, 10:36 am, dj3va...@caffeine.csclub.uwaterloo.ca (Dave
Vandervies) wrote:
In article <1166551672.835525.76...@t46g2000cwa.googlegroups. com>,
Dec 19 '06 #5

P: n/a

<st*********@gmail.comwrote in message
news:11*********************@t46g2000cwa.googlegro ups.com...
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
to #include <stdlib.h>
...
return foo_p_C;
}
--
Fred L. Kleinschmidt
Boeing Associate Technical Fellow
Technical Architect, Software Reuse Project


Dec 19 '06 #6

P: n/a
"Rg" <rg*****@gmail.comwrites:
You seem to be misunderstanding two different concepts...
[snip]

Please don't top-post.

Read the following:

http://www.caliburn.nl/topposting.html
http://www.cpax.org.uk/prg/writings/topposting.php

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Dec 19 '06 #7

This discussion thread is closed

Replies have been disabled for this discussion.