Skip to main content
GameDev.net gamedev.net
🔒 Locked

pointer poo

Started by sammyjojo Apr 22, 2003 at 10:23 PM 18 replies 1.5k views
Original Post
sammyjojo
sammyjojo
Okay i though i understood pointers pretty well, but i guess i don''t, could someone please tell me why this program doesn''t work... #include <stdio.h> struct Test { int a; struct Test *next; }; void GoHere( struct Test *ptr ) { struct Test *newPtr = NULL; newPtr = (struct Test *)calloc( 1, sizeof(struct Test) ); newPtr->a = 5; newPtr->next = NULL; ptr = newPtr; printf( "looky - %d\n", ptr->a ); } int main() { struct Test *first = NULL; GoHere( first ); ---> printf( "looky - %d\n", first->a ); return 0; } When it gets to the part with the arrow, why doesn''t it display 5, instead it just crashes and I don''t understand why. After GoHere is exectured first is supposed to point to newPtr, but it doesn''t This is driving me mad....
kdogg
kdogg
newPtr is a local variable in the function GoHere(). After GoHere returns, there is no guarantee that pointer will still point to anything.
sammyjojo
sammyjojo
Oops, i meant to post this in general programming Well i thought since newPtr is dynamically allocated, then first pointer which was passed into GoHere() as ptr would still be able to point to it even though newPtr would go out of scope, is this not right?
sammyjojo
sammyjojo
Hmm, okay that makes sense. Well I was trying to make a linked list sort of thing without making the pointer to the first object in the list a global variable (which is the way i used to do it). I want to take something like this...

struct Object {
int a;
struct Object *next;
struct Object *prev;
};

struct Object *gFirstObject;

void NewObject()
{
struct Object *newObject;
newObject = (struct Object *)calloc( 1, sizeof(struct Object) );
/*do object init stuff here*/

/*put object in list based off gFirstObject, details missing */
gFirstObject->next = newObject;
newObject->prev = gFirstObject;
}

int main()
{
NewObject();
return;
}

That up there used to work for me (nearly positive it did, but could be wrong), but if i want to do it without using a global variable for the first object i tried somethinglike this....

struct Object {
int a;
struct Object *next;
struct Object *prev;
};

void NewObject( struct Object *firstOne ) <--- not firstObject?
{
struct Object *newObject;
newObject = (struct Object *)calloc( 1, sizeof(struct Object) );
/*do object init stuff here*/

/*put object in list based off gFirstObject, details missing */
gFirstObject->next = newObject;
newObject->prev = gFirstObject;
}

int main()
{
struct Object *firstObject

NewObject( firstObject ); <--- is this not passing this pointer?
return;
}

This doesn't work and it's making me really confused. I guess i'm not passing the pointer or am I. Are you saying that I'm making the pointer point to something that goes out of scope, but doesn't that happen with the global variable version too? But the global version works i believe. I hate it when i think i understand something, but i really don't have a clue If you happen to understand what i'm getting at, how would i go about using a firstObject variable that's not global?

[edited by - sammyjojo on April 23, 2003 1:01:12 AM]
LockePick
LockePick
EDIT: Won't go into the details, but I'm sorry if what was posted here confused matters (bumped the thread at least). Take it as a lesson to always well protect your login passwords, so you don't end up looking as stupid as me :D

[edited by - LockePick on April 25, 2003 7:26:47 PM]
sammyjojo
sammyjojo
The gFirstObject''s in the second code section are supposed to be firstOne''s, I messed up Well, i can understand what your doing in your example, but after thinking more on this, why is it that if you use a global variable you allocate memory in a function and then make the global varible point to it, you can still access the memory later on. If you don''t use a global variable and instead use a local variable that points to the first object and just pass it to functions for them to make that variable point to something, it doesn''t point to anything after the functions exits?

Basically going back to the first code that i put up, why is that "first" doesn''t have a value in it after returning from GoHere(), since GoHere() allocates memory and makes "ptr" (which is actually "first") point to the newly allocated memory. Even if what it''s pointing to goes out of scope, shouldn''t "first" at least have the address of the gone-out-of-scope-memory as it''s value after returning back to main()? Am I not passing "first" so that GoHere() could modify it? Is it being passed right so this can happen? Thanks for all the help everyone, I''ll understand it someday
akiinao
akiinao
quote:
Original post by Anonymous Poster
The correct way to do it:

void GoHere( struct Test **ptr )
{
struct Test *newPtr = NULL;

newPtr = (struct Test *)calloc( 1, sizeof(struct Test) );
newPtr->a = 5;
newPtr->next = NULL;

*ptr = newPtr;
printf( "looky - %d\n", ptr->a );
}

int main()
{
struct Test *first = NULL;

GoHere( &first );

...


OPTIMIZE THE CODE:



void GoHere( struct Test **ptr )
{
*ptr = (struct Test *)calloc( 1, sizeof(struct Test) );
(*ptr)->a = 5;
(*ptr)->next = NULL;

printf( "looky - %d\n", (*ptr)->a );
}

int main()
{
struct Test *first = NULL;

GoHere( &first );

...
akiinao
akiinao
quote:
Original post by Anonymous Poster
The correct way to do it:

void GoHere( struct Test **ptr )
{
struct Test *newPtr = NULL;

newPtr = (struct Test *)calloc( 1, sizeof(struct Test) );
newPtr->a = 5;
newPtr->next = NULL;

*ptr = newPtr;
printf( "looky - %d\n", ptr->a );
}

int main()
{
struct Test *first = NULL;

GoHere( &first );

...



AtelierVisca
AtelierVisca
Pointers cannot, under ANY circumstances, go out of scope. That''s why you have to use the appropriate clean up routine (delete, free, etc). The actual problem with this example is in how you are allocating the memory.

calloc() is used for allocating arrays ...

if you use malloc() or new instead, you would be fine.

- James
James
sammyjojo
sammyjojo
So basically i was passing the first object pointer by value instead of by reference? Well, i feel stupid
Trienco
Trienco
what you seem to tell him is that the memory will "go out of scope" just because he's assigning the returned address to a local pointer.. that would be complete nonsense. first: alloc doesnt care or even know what you assign the returned value to and second this memory will stay allocated until he calls free on it.
btw. the whole idea of memory "going out of scope" is weird enough to make me wonder where you got this from?

"No. You told your original pointer (first) to point at another pointer which was about to go out of scope (newPtr)."

arg.. its a pointer to a struct so i CANT point to a pointer without typecast. the whole point is that ptr is just as local as newPtr is and even though he's copying the address stored in newPtr to ptr it doesnt matter, because ptr will go out of scope just like newPtr.

one way to solve this would be Test **ptr with *ptr=newPtr;

i think youre version will cause some headache when creating the first element as he cant pass a "first". also his version will make ptr point to the created object whereas yours will make ptr->next point to the created object.

"//again, you should not be assigning "next" to a pointer that will go out of scope. You should be allocating memory directly into "next"
gFirstObject->next = newObject;"

its getting funny to see someone who didnt understand pointers half as much as sammy try to explain him something that doesnt make any sense and probably confuse the hell out of him.

newObject is nothing but a number thats the address of memory and after copying this value to bla->next it absolutely and in no way matters what happens to newObject after that. what you are talking about would mean to write bla->next=&newObject with bla->next being a Test** which it definitely isnt.

the one and only problem is that ptr is local, because his function uses call by value which will simply copy the value of first to the local ptr and not touch the original first in any way. making the function either Test*& ptr or Test** ptr is necessary to work on the original first. and yes, once thats done its easier to assign the result of malloc directly to either ptr (if using Test*&) or to *ptr (if using Test**.. as all the above is plain c and therefore even alien looking with the struct hanging around all the time i assume he will use the latter).


and now i spent so much time writing this and trying to hold that the answer became pretty obsolete.
btw. this reminds me of a really "great" c++ tutorial telling me this:
"int a,b,c;
int a=b=c; //from now on a,b and c will have the same value
c=5; //a,b and c are now 5"

i always wonder why someone who opened his "c for complete dummies" book 5 minutes ago would bother to write tutorials before he even understood the most basic things.

[edited by - Trienco on April 23, 2003 1:50:00 PM]
f@dzhttp://festini.device-zero.de
AtelierVisca
AtelierVisca
quote:
Original post by sammyjojo
So basically i was passing the first object pointer by value instead of by reference? Well, i feel stupid


Sort of ...

You were trying to allocate an array of Test*'s, which is different than allocating a single Test*.

// allocate an array of structs that is 1 long
// same as Test* p[1];
Test** pArray = NULL;
pArray = calloc( 1, sizeof(Test) );

// allocate a single instance of a Test struct
Test* pTest = NULL;
pText = malloc( sizeof(Test) );

- James

edit: what i'm saying about allocation stands, but when passing to a function as a parameter that's being modified, you should follow what Heaven is saying below.

[edited by - AtelierVisca on April 23, 2003 4:23:44 PM]
James
Heaven
Heaven
AP beat me to it, at least conceptually, but I was gonna'' say that the way I do it is with a ref:


  
#include <stdio.h>

struct Test {
int a;
struct Test *next;
};

void GoHere( struct Test * &ptr ) // <----- NOTE USE OF &

{
struct Test *newPtr = NULL;

newPtr = (struct Test *)calloc( 1, sizeof(struct Test) );
newPtr->a = 5;
newPtr->next = NULL;

ptr = newPtr;
printf( "looky - %d\n", ptr->a );
}

int main()
{
struct Test *first = NULL;

GoHere( first );

---> printf( "looky - %d\n", first->a );

return 0;
}


A pointer is a 4 byte container variable which holds the address of a block of memory.

The physical address of the container variable used to hold the address of a block of memory is that variable''s "reference" (e.g., &ptr).

When you do newPtr = calloc() you fill newPtr with a pointer to a block of memory. When newPtr goes out of scope the memory is still out there, but you lose the pointer to it because newPtr is discarded/invalidated.

Assigning ptr to newPtr does make ptr contain the same pointer as newPtr, but because of the way you pass ptr to the GoHere() function you restore its previous contents when you leave GoHere().

Something like this:

create temp pointer called ptr and assign it to first (i.e., ptr = NULL)
push ptr onto the stack
do GoHere() (ptr gets assigned contents of newPtr)
pop ptr off of the stack (i.e., ptr = NULL because it was pushed as NULL)
assign first contents of ptr (i.e., first = NULL)

First is then invalid and first->a gets you an exception.

If, however you pass first as the address of a pointer to a Test structure (i.e., struct Test * &ptr) then what you''re doing is actually modifying first by proxy. Why? Because...

create temp pointer called ptr and make it a reference to first (i.e., &ptr = &first)
push ptr onto the stack
do GoHere() (ptr gets assigned contents of newPtr, which means first gets assigned contents of newPtr)
pop ptr off of the stack
assign first contents of ptr (i.e., &first = &ptr)

Or something like that. The main concept is that you''re actually passing first by REFERENCE, since ptr is actually just another name for first (i.e., &ptr = &first). Anything you do with ptr in the function is actually getting done to first as well.

I hope that''s clear and/or helps a bit. If not, I apologize. It''s the best I can do with my limited understanding of this pointer stuff.

Take care.

Florida, USA
RTS Engine in Development
http://www.knology.net/~heaven/rts.htm
Jesus is LORD!
Florida, USA
Current Project
Jesus is LORD!
VietCoder
VietCoder
Hi,

I don''t read previous post, so i may reapeat...

When you exit the function all disappear !
One solution is use double-pointer, other solution is to save information (and not address, like you do) but in this case you pointer must be allowed, else it''ll crash. The first solution i better i think.

++
VietCoder
chiuyan
chiuyan
wow, i have never seen so many completely wrong replies to a post before.

I know some people have pointed this out (like Heaven and the AP), but the memory pointers point to does not go out of scope. when you allocate memory, the OS/Runtim/Whatever does not care what variable you store that pointer in. The memory does not get freed until you explicitly free it (with free, or delete, or whatever).

The problem with your post is that you pass in the pointer to the function by value, nor by reference. That means the compiler makes a copy of it, so whatever changes you make to that variable inside of the function only affect the copy, they do not affect the variable outside of the function. You need to pass the variable into the function by reference if you want its value to be changed.

It really doesn't matter if you call calloc or malloc. the only difference is the parameters you pass in.

[edited by - chiuyan on April 23, 2003 8:00:56 PM]
rypyr
rypyr
quote:
Original post by chiuyan
wow, i have never seen so many completely wrong replies to a post before.

I know some people have pointed this out (like Heaven and the AP), but pointers do not go out of scope.



Way to add your own "wrong reply" to the stack.

Pointer variables CAN go out of scope, just like any other variable. Pointer variables are not magic in that respect. However, the MEMORY which they point to is not de-allocated.


void allocInt(bool b)
{
if(b) {
int* pint = new int[20];
} // <== pint goes out of scope here, but its memory
// stays allocated, this is a memory leak unless you
// store pint's value somewhere that doesn't get
// descoped until its memory is de-allocated
}



As long as everyone is nitpicking I thought I'd join the fray!

Regards,
Jeff

Edit: broke up my long comment into multiple lines to make it nicer...

[edited by - rypyr on April 23, 2003 8:01:14 PM]
Trienco
Trienco
,-) at least you can be sure he meant the right thing even if it came out wrong. still a lot better than suggesting that a function will in some mysterious way care about where you store its return value.
f@dzhttp://festini.device-zero.de
sammyjojo
sammyjojo
so many replies Well, i''ll try out what i''ve learned so far and see where that gets me, that is if i''m not confused already Thanks for all the help everyone!
Skizz
Skizz
Have a look at this code:

  
#include <stdio.h>

void GoHere( int ptr )
{
int newPtr = 5;

ptr = newPtr;
printf( "looky - %d\n", ptr );
}

int main()
{
int first = 0;

GoHere( first );

printf( "looky - %d\n", first );

return 0;
}

All I''ve done here is convert the ''struct Test *'' type into an int. The output from this will be:
looky - 5
looky - 0
Hopefully you''ll understand why you get that output.
Now why should that behaviour change when the type is a pointer? To the CPU they are the same thing (just numbers) and the compiled code is identical.
The key is to remember that in C/C++ arguments are *passed by value* and not by reference unless a ''&'' appears in either the function definition (i.e. a C++ reference) or the parameter list (i.e. address-of).
When passing by value, a copy of the original is passed to the function and the original value remains unchanged - regardless of its type (class, pointer, struct, whatever).

Skizz

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.