Sign in to follow this  
blanky

Pointer Insomnia

Recommended Posts

Okay guys, I'm a C/C++ 'programmer', the quotes because I'm great at everything but pointers, even though I can do, still kinda confuse me, and since pointers are practically what those languages are all about, I can't really call myself a programmer :(. I've read tutorials/articles, read books, googled my head off, and all I find is the occasional
int myint = 9;
int *pmyint = &myint;
*pmyint = 4; // now myint is equal to 4
Okay, I understand that, absolutely, I understand pointer arithmetic as well (Iterating and the like), however, I get confused when someone does (I'm making this up, not that it actually works, but you'll get the idea) something like (*(char)&something), so they use them all weird, &(*thing(&something)), remember, I made that up, but that's what it looks like to me, I think it has something to do with casting, I might be able to understand that. However, where the big confusion for me comes in, is when people create, say, functions that take in either pointers or references, which ones and why? Like, someone takes in an int *thing, but inside the function, treats it as &thing, or the other way around, I think that means that now the function can have direct control over the variable which thing points to, but, man it's hard to explain. Like, basically, they pass one thing (say, a pointer), and but treat it another way, how do you know why to treat it that way? Er, nevermind, in the process of typing this up I think I get it, but if you guys can help out I'd really appreciate it, this thing's driving me crazy. I know that: int *thing *thing = the actual thing it points to thing = the address? So if: int mynum = 9; int *thing = &mynum; *thing = 9 thing = address of mynum ? And basically you pass references or variables to not duplicate variables and therefore speed things up? But why pass references/pointers, which one? And when? function(int *thing) or function(int &thing)? Thanks, I hope I didn't confuse anybody, I'm so confused myself, really would appreciate any help :'( EDIT: For example, what's that all about, when you do something like (*WORD)&something, or something like that, which supposedly makes the first WORD sized part of variable something equal to whatever, or something like that? [Edited by - blankdev on April 16, 2006 3:37:21 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by blankdev
int *thing

*thing = the actual thing it points to
thing = the address?

So if:


int mynum = 9;
int *thing = &mynum;


*thing = 9
thing = address of mynum ?

And basically you pass references or variables to not duplicate variables and therefore speed things up?

Yes this is correct, except that "or" should be an "of". If you meant or then no, with variables you just pass by value (in C and C++ at least) so you will still be doing the copying.


Quote:
But why pass references/pointers, which one? And when? function(int *thing) or function(int &thing)? Thanks, I hope I didn't confuse anybody, I'm so confused myself, really would appreciate any help :'(


You pass references if you just want to avoid the unnecessary copy, an reference can be though of as just an alias. The interresting thing about a reference is this:
int mynum = 9;
int& mynum_ref = mynum;
mynum_ref = 9;
&mynum_ref = address of mynum
So it's not a copy, just another name for mynum. So if you did this:
mynum_ref = 10
then mynum would also be 10, since they refer to the same object. You can think of a reference as a pointer with simplified syntax, but the compiler can implement them in any way it wants. The reason some people pass by pointer to avoid copying data is that C doesn't support references, so code with a C interface can't use references (think Win32). Another reason to pass by pointer (which is not related to copying) is that dynamic polymorphism is generally achieved with pointers.

Share this post


Link to post
Share on other sites
The difference between function(int *thing) and function(int &thing) is precisely that in the former NULL is a valid parameter value, but in the later, it is not. References are preferred in C++, but if you want NULL to be a valid parameter, then use a pointer.

Here is a simple example which continues on from your first example:
int myint = 9;
int *pmyint = &myint;
*pmyint = 4; // now myint is equal to 4

int &rmyint = *pmyint
rmyint = 7; // now myint is equal to 7
What these last two lines do: First we declare a reference, as noted by using & instead of *. A reference is like a pointer, but operates at a different level of indirection than pointer, to basically hide the fact than a pointer is even involved.

When you assign to a pointer you give it the address of something, which usually means you have to get the address of that thing, using & (your line 2 above)

When you assign to a reference (which you can only do once) you give it the actual thing, and it internally gets the address of that thing all by itself. So in order to give it the int that pmyint points to, we have to dereference the pointer to get back to the actual value. We then assign this back to the reference, which internally gets the address of this int. We could instead have done
int &rmyint = myint;

You may have been scared off by something like
long foo = 0xFEDCBA98;
*((char*)&foo) = 0x12;
Okay, lets work out this left hand side.
Start at the variable, foo. It has an & in front of it. That means we're taking its address. So that means we get a long* or a pointer to a long. However, just in front of that we're telling the compiler to cast it to a char* or pointer to a char. This is fine, all pointers are just memory addresses, so it will quite happily pretend that the memory address now points to a char. The memory address is of course the same size, regardless of what it points to. Next it takes that whole thing and puts a star at the front. Now just like your line 3 above it means that we're now looking at what that all points to. It is of course still pointing to foo, but it no longer sees foo as a long, it thinks it is looking at a char. So the assignment now only causes it to overwrite a char.
The result is that foo now equals 0xFEDCBA12 (little endian machine here).

Share this post


Link to post
Share on other sites
Quote:

...something like (*(char)&something), so they use them all weird, &(*thing(&something)), remember, I made that up, but that's what it looks like to me, I think it has something to do with casting...


Yep, that has to do with typecasting. iMalc explains it well, I just wanted to add that typecasting requires using a typename. A variable name will produce a compile time error.

So, if thing is the name of a variable (as in the examples),

&(*thing(&something))

won't compile. The leading asterisk would dereference the thing variable and you can't typecast one variable as another variable. If thing is the name of a type, it won't compile either because a typename isn't a variable and can't be dereferenced. The asterisk must follow the typename to indicate that the typecast is to a pointer to that datatype eg. (typename*)&something.

What is happening here can be thought of as "overlaying" a new type onto the underlying memory.

Share this post


Link to post
Share on other sites
Lol thanks, yeah I made that up, since that's what it all looks like to me. Anyways, thanks all three of you, very helpful, I really really appreciate it.

Quote:

Okay, lets work out this left hand side.
Start at the variable, foo. It has an & in front of it. That means we're taking its address. So that means we get a long* or a pointer to a long. However, just in front of that we're telling the compiler to cast it to a char* or pointer to a char.


Ah okay, so instead of treating it like a pointer to a long, we're treating it like a pointer to a char? Okay (I hope) I got it.

Quote:

This is fine, all pointers are just memory addresses, so it will quite happily pretend that the memory address now points to a char. The memory address is of course the same size, regardless of what it points to.


Okay :)

Quote:

Next it takes that whole thing and puts a star at the front. Now just like your line 3 above it means that we're now looking at what that all points to. It is of course still pointing to foo, but it no longer sees foo as a long, it thinks it is looking at a char. So the assignment now only causes it to overwrite a char.
The result is that foo now equals 0xFEDCBA12 (little endian machine here).


Ohhh! I think I get it! So instead of making a pointer variable, and making it equal to a reference of another variable and all that, we do that all in one line? Ohh I get it now! I was gonna ask 'how is 0x12' a char? But I'm guessing it's its ASCII equivalent in hex? I get it now, thanks sir! And since you have a little endian machine (or whatever) it adds it to the end? And it doesn't add it but overwrites it, I get it now! (Hope I didn't misinterpret anything), thanks guys! Thanks iMalc!

Share this post


Link to post
Share on other sites
Quote:
Original post by blankdev
I was gonna ask 'how is 0x12' a char? But I'm guessing it's its ASCII equivalent in hex?


A char variable doesn't necessarily equate with an ascii character.

Share this post


Link to post
Share on other sites
Blandev, I would like to add that, a pointer of type X is just a variable like any other variable, except that, it stores a different kind of value: an intregal address (to another variable). Passing by address/reference as oppose to value, in a function call, will usually provide lesss overhead, make the function call more efficient, reflect changes to the variable in the calling function and, potentially speed up the function call.

So, if you had an object (e,g.: struct, class - a declaration of any of these is also a variable) which consisted of 30 data members, of which each were at least 1 byte long, your object would be at least 30 bytes long, and, passed it by value to function Foo, the functions stack/data frame would create space for 30 bytes on every call to it - on the stack (temporary storage) - copy the original objects data members values over and, any changes made to it would not reflect the object (variable) in the calling function. If the object was passed by address or reference, function foo's stack frame would create space (on every call) for the size of a pointer/reference. The size of a pointer is typically 4 bytes on a 32-Bit system and, any changes you make to this object via the pointer/reference would reflect on the object in the calling function. See the potential benefit pointers/references can be?

Hasta entonces =)
- xeddiex

Share this post


Link to post
Share on other sites
Ah, thanks :) But then why not always do it by reference/pointer instead of variable? Just wondering.

Share this post


Link to post
Share on other sites
Quote:
Original post by blankdev
Ah, thanks :) But then why not always do it by reference/pointer instead of variable? Just wondering.


Sometimes, there's no need to. For example, if you don't care about modifying an object passed into a function, then pass by value, else pass by address/reference.

Clarification: I say address and not pointer because the type and identfier in the actual argument of the function definition is the actual declaration of *a* pointer to type X, whereas, the address being yielded in the formal argument (function call) is usually not an address being yielded from a pointer, but an address of a normal variable such as int.

- xeddiex

Share this post


Link to post
Share on other sites
If you have no need to modify a variable that is not a POD(int,char,float,etc..) type your generally better off passing it by a constant reference than simply by value.

Share this post


Link to post
Share on other sites
Quote:
Original post by moeron
If you have no need to modify a variable that is not a POD(int,char,float,etc..) type your generally better off passing it by a constant reference than simply by value.



However, there are times when it is better to pass something by it's address when it's a big structure or something. Take this example:

struct
{
int a;
int b;
int c;
char *cSomeString;
} SomeStruct;

//look at these two functions prototypes
void SomeFunction(SomeStruct StructVariable);
void SomeFunction(SomeStruct *StructPointer);



with the 1st functions, the compiler will have to copy the whole structure to SomeFunction, whereas, with the 2nd function, it will only have to pass the pointer address, which is just a register (or 1 space on the stack).

So, basically, if you have a large structure, sometimes you should pass by pointer (or reference) to save on performance.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by CTar
You pass references if you just want to avoid the unnecessary copy, an reference can be though of as just an alias. The interresting thing about a reference is this:
int mynum = 9;
int& mynum_ref = mynum;
mynum_ref = 9;
&mynum_ref = address of mynum

A reference resides at its own address. What thinking of are union members.

Share this post


Link to post
Share on other sites
Okay guys, I really appreciate the help you've given me, I've finally (almost) learned what I've never come around to learning. But anyways, I seem to be having some problems with the following, I might not be able to recreate the situation entirely 100 percent correct, but I think you'll catch on. So it's got to do with functions, well, not really. Watch, say we have:


void function(int *apples, int &oranges, int bananas)
{
// stuff
}




So we're accepting three arguments, a pointer to an int, a reference of an int, and an integer called bananas. So what's the problem? Well, it's pretty complicated. So, we know that we can (Can we?) pass other things besides that, for example


function(&var1, *var2, var3);




Right? So basically what we're doing is allowing the function to modify var1 and var2's values right? Anyways, we could also (Er, can we? Would it be different?) pass this stuff:


function(*var1, &var2, var3);




Er, could we? I have the slightest feeling that var1 would be a pointer to a pointer, cause it's accepting a pointer in the first place, er, so would you do this? (If var1 is already a pointer (int *var1)).


function(var1 /*etc*/);




So basically, I'm confused as to what to pass how. And it gets more confusing to me when we're actually using the variable within the function, I've seen source that for example, you pass a pointer, and treat it as a pointer within the function


void function(int *apples, int &oranges, int bananas)
{
*apples = *apples++;
// etc
}




However, at the same time, I've seen this happening


void function(int *apples, int &oranges, int bananas)
{
apples blah blah blah // instead of *apples
// etc
}




Hmm...apples without the little pointer operator would mean it's address right? and *apples is the actual value of apples? But then, what would &apples be? Isn't that also the address of apples? Or what it points to I mean, unless one is the address of the pointer and one is the address of what it points to? Is there even such thing? I don't think a pointer has an address but then again what do I know.

Then there's the


void function(int *apples, int &oranges, int bananas)
{
&apples blah blah blah // instead of *apples or apples
// etc
}




So, here we're modifying apples' value? That is, the value of the variable it points to? Man, I'm very confused and I know that you guys are getting this a different way than what I mean, if I could only find that one thread...but I have no idea of what forum of what site it'd be in. It was something like, 'if one of the function's arguments is a pointer, and you pass a pointer, then it'd be a pointer to a pointer', something like that, obviously I'm not saying that's right, but it was something like that, a chart, so I could know what to pass and how to treat each thing. I'm sorry guys, I have a feeling I don't make sense and this is kind of confusing, so, nevermind :'(

The forum thread said something like this, I don't remember correctly at all so this is most likely wrong:

If you have

int *thing;

and you have function prototype

function(int *arg1);

If you pass it like so

function(int *thing);

It'd treat it X way

If you pass it like so

function(int thing);

It'd treat it Y way

Sorry for the confusion guys

Share this post


Link to post
Share on other sites
Quote:
Original post by blanky
Sorry for the confusion guys


Yeah, you are very confused.

A pointer (e.g.: int *apples) is a variable. All variables and anything that holds data, such as the above, has to itself have some memory associated with it to be *able* to hold other data. apple has an address (== memory) for itself, aswell as what it currently holds - an address of another variable. When you use the ampersand on apple (&apple) you are producing the address of the variable apple. When you use the variable apple itself (apple), you are exposing the address of the variable it currently holds (or points to; the pointee). When you use the dereference operator on apple (*apple), you're applying the operator not to the apple variable, but to the address (of another variable) apple currently holds, essentially, you're accessing the final-value (an int) of the variable that apple currently holds, or points to.

I rec you watch this video: Binky Pointer Fun Video [grin]

EDIT: The following is a group of links that teach-up on pointers:

more Pointers
some more Pointers
and even more Pointers

The later one is one that I read through a couple years ago when I was learning pointers too.

- xeddiex

Share this post


Link to post
Share on other sites
:'( I have a feeling I'll never get this, thanks for being so kind though, I'll keep trying :'( Thanks for the links and help :')

Share this post


Link to post
Share on other sites
Quote:
Original post by blanky
:'( I have a feeling I'll never get this, thanks for being so kind though, I'll keep trying :'( Thanks for the links and help :')


Don't feel that way man. I too, was once in your situation. I thought I would never, ever learn to use or understand how pointers work. I just kept on trying and never gave up. I posted questions on it, here (under another name), and one day, it just finally clicked. Pointers are VERY easy to work with once you know them. They are also extremely powerful. I cannot imagine working without them in C, and maybe even C++. I started with C - for 3 years, and now I'm currently learning C++. I can happily skip the pointers part though, hehe, thanks to my previous experience in C.

Just don't get discouraged, it's normal to feel like this is an extereme topic to comprehend and that you'll never get it, but, trust me, if you don't give up, you'll eventually get it too. It's not a matter of IF, it's a matter of WHEN.

- xeddiex
[p.s, Don't be afraid to ask questions - someone will always be willing to help you out]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
[quote]Original post by blanky

void function(int *apples, int &oranges, int bananas)
{
apples blah blah blah // instead of *apples
// etc
}


[/quote]
Okay, remember that apples is a copy of a pointer, so modifying apples does not change the address stored in your passed pointer. Additionally, I've noticed you've been referring to the concept of pointer-to-pointers in your post. I'm pleased to announce that none of your examples use pointer-to-pointers. If you don't want to allow the address stored in apples to change, declare it as an int* const apples (not to be confused with const int* apples or int const* apples). This notation makes it so that the address stored in a pointer can never change. The only real differences between a constant pointer and a reference is that a constant pointer can be deleted1, and pointers can be used for pointer arithmetic.

[quote]

function(*var1, &var2, var3);


[/quote]
Don't worry, you can't pass a non-pointer to a pointer parameter, nor the address of a variable to a reference.

There are more parts to this subject, but try to wrap your head around this first.

1Well, a reference can be deleted, but you'd need to use a little trickery to do it; a trick that is vile.

Share this post


Link to post
Share on other sites
Pointer are one of those things that, once you finally get it, it all clicks into place. When you understand it, you'll be like, "Ahh, it all makes sense now" and you'll feel like you can do anything. Understanding pointers leads to a deeper understanding of computers in general as well.

As for your examples, there's a few problems. Let me show some examples that might or might not help.



int Var1 = 1;
int Var2 = 2;
int Var3 = 3;

// I use 'p' in front to denote a pointer, and 'r' to denote a reference
void func1(int *pParam1, int &rParam2, int Param3);

// to call func1, the 1st parameter must be a pointer to int type, the other two must be int types

// this is valid

func1(&Var1, Var2, Var3);
// you must take the address of one of the variables (Var1)
//and pass it as a pointer. Now, you are literally passing the
//address of Var1 to func1

// The program will also pass the address of Var2 as the second parameter since it is a reference, but it is all hidden from you by the compiler.

// Var3 is just passed by value, so it is actually sending 3 as the value to func1


void func1(int *pParam1, int &rParam2, int Param3)
{

// to change the value passed by pParam1, you have to dereference it with the * operation
*pParam1 = Param3;

// now you can change the actual value of rParam2 as well
// but you don't need to dererefernce it
rParam1 = Param3;

// this next line does nothing, since the actual value of Param3 won't change when you exit func1
Param3 = 0;

}

// the below will ***NOT*** work

func1(*Var1, &Var2, Var3);
// to use the * operator, the variable must have been a pointer, but Var1 is an int
// &Var2 won't work because you must pass an int to the function, but you are now passing a pointer to an int, and the compiler will barf
// Var3 is OK



now, what will the following program do?


int main (void)
{
int Var1 = 1;
int Var2 = 2;
int Var3 = 3

printf("Variables are %d %d %d\n", Var1, Var2, Var3);

func1(&Var1, Var2, Var3);

printf("Variables are %d %d %d\n", Var1, Var2, Var3);
}



I hope I helped.

Share this post


Link to post
Share on other sites
One of the most important ideas for understanding poitners ... a picture.

DRAW the layout of you objects in memory on a piece of paper ... using a fairly standard size box for each byte, inside the box, write what is stored IN the memory, above the box write the address of that memory.

so if I have:

int x = 3;
char text[] = "123";

I might draw it like:

0x80284852
---------------------
| 03 | 00 | 00 | 00 |
---------------------

0x80284856
---------------------
| 31 | 32 | 33 | 00 |
---------------------

And I usually don't worry about endianness until it matters. In the above, I wrote the hex values seperate, which I only do in real life when I'm starting out, or very concerned about exact byte placement ... normally I would just do:

0x80284852
-------------
| 3 |
-------------

0x80284856
-------------
| '123\0' |
-------------

And then we add the idea of a pointer and a reference to this system:

int x = 3;
char text[] = "123";
int *currentValue = &x;
char *currentLetter = text; // an array name by itself is the same as a pointer to the first item.

0x80284852
-------------
| 3 |
-------------

0x80284856
-------------
| '123\0' |
-------------

0x80284860
-------------
| 0x80284852|
-------------

0x80284864
-------------
| 0x80284856|
-------------

See how I very clearly distinguish which are pointers, by putting strange numbers that start with 0x80 in the box (that's just an arbitrary fake address, because rarely in your program do you use ints over 2 billion).

I also typically draw arrowed lines from the pointer box to the box it points to ... showing the logical relationship. I use pencil for these lines when debugging an algorithm (as I do for the values in the boxes) because they may change while running).

References get a little harder if you are trying to correctly model them in terms of compiler treatment, but when it comes to function passing, I model them EXACTLY as I would const pointers in the diagram.

0x80284864 (ref)
-------------
| 0x80284856|
-------------

When using both pen and pencil (I always use pen as personal habit, unless I need rewriting), I write const values and reference lines in pen ... since they don't change.

Share this post


Link to post
Share on other sites
Thanks guys! I'm sorry I just realized that you guys replied to this lol, thanks thanks thanks.

EDIT: I really appreciate it. See, my problem's not with the, er, 'actual' pointers themselves, I mean, of course it is but, not completely. I know what they are, etc. It's just that I get confused with things such as, say, the complicated pointer casts and what to pass when.

So when it accepts a reference, you pass a normal variable type, not a pointer to a variable. When it accepts a pointer, you pass a reference to a variable right? Is there more to this? Thanks.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this