Pointer Insomnia

Started by
19 comments, last by blanky 17 years, 12 months ago
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]
Advertisement
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.
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 4int &rmyint = *pmyintrmyint = 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).
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms
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.

"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
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!
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.

"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
Oh, yeah I think I knew that, I just figured. :D I'm so happy I know this now, thanks guys.
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
one..
Ah, thanks :) But then why not always do it by reference/pointer instead of variable? Just wondering.
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
one..

This topic is closed to new replies.

Advertisement