449,243 Members | 1,141 Online
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
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>, All Beginner/Intermediate level question. I understand that returningptr 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 usingfoo_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 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 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 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 ... return foo_p_C; } -- Fred L. Kleinschmidt Boeing Associate Technical Fellow Technical Architect, Software Reuse Project Dec 19 '06 #6

 P: n/a "Rg" San Diego Supercomputer Center <* 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.