• Advertisement
Sign in to follow this  

Easy pointer question

This topic is 3627 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Sorry if this has been answered elsewhere but I couldn't seem to find anything and I'm a bit confused. Going through linked lists in my book and it has the following method:
template <class Entry>
void linkedlist<Entry>::copylist(listnode<Entry> *&newlist, listnode<Entry> *oldlist);



I'm a bit confused about the first parameter as I've never seen this before (the pointer to a reference). While I'm on the subject I've seen pointers that look like "double pointers" (e.g. **dblPntr) that I'm confused about as well. If someone could at least point me in the right direction on this I would appreciate it.

Share this post


Link to post
Share on other sites
Advertisement
I'm note sure but could it be that for the listnode type the * or the & operator has been overloaded?

If not i would like to know the answer to your qestions also.

Share this post


Link to post
Share on other sites
Unfortunately not, the listnode is a very simple class

[sourcelang="cpp"]
template <class Entry>
class listnode
{
friend class linkedlist<Entry>;

private: Entry *data;
listnode *next;
};

Share this post


Link to post
Share on other sites
The type of the first parameter should be read as "reference to pointer to listnode<Entry>". It has the usual reference semantics, with modifications affecting the actual pointer passed as the argument.

Share this post


Link to post
Share on other sites
Zao:
I think I understand what you are saying. If I understand this correctly I can set this variable to NULL, and this would effect the "original" variable I passed to the function as well?

Share this post


Link to post
Share on other sites
Quote:
Original post by gsGomer
Sorry if this has been answered elsewhere but I couldn't seem to find anything and I'm a bit confused. Going through linked lists in my book and it has the following method:

*** Source Snippet Removed ***

I'm a bit confused about the first parameter as I've never seen this before (the pointer to a reference).


Types are read backwards. (You wouldn't say "an int to a pointer", right?) So this is in fact a reference to a pointer-to-listnode<Entry>.

Quote:
While I'm on the subject I've seen pointers that look like "double pointers" (e.g. **dblPntr) that I'm confused about as well. If someone could at least point me in the right direction on this I would appreciate it.


A pointer to pointer to T is simply a pointer to (pointer to T). Pointers are "things" in their own right, and as such, can be pointed at. And also referred to; hence the original question.

Share this post


Link to post
Share on other sites
Quote:
Original post by Shakedown
While **something is fine, I imagine that &&something is not. Am I correct?


&&something is wrong (unless some strange operator overloading with unary '&' is taking place, but that is wrong on a whole different level).

What is fine is:

Something something;
Something *onceRemoved = &something;
Something **twiceRemoved = &onceRemoved; // almost like &&something

Share this post


Link to post
Share on other sites
Put simply, you pass a function a pointer to T,

1) When you want to avoid the costs related with copying T back and forth, or

2) When you want to change T inside that function.

But accessing T via a pointer requires -> operator. Besides, every time you want to access the data that the pointer points to you have to dereference that which is a pain in the rear end and results in cluttered code, so you could have easily passed a reference in the first place and enjoy all the benefits of passing by reference (as opposed to passing by value) AND the freedom of changing T inside the function, but without all the hassles of dealing with pointer syntax. It has the same effect, you just let the compiler do all that pointer manipulation for you behind the scene.

You pass a pointer to pointer to T,

1) When you want to change the pointer that points to T, like when you want to let a function allocate some memory for you. The following code won't work.


void AllocateMemory( unsigned char* pBuffer ) {
pBuffer = new unsigned char[ 100 ];
}

int main() {
unsigned char* pBuffer;
AllocateMemory( pBuffer );
}





Will the above code compile? Yes, but will that do what you're expecting from it? No. Why, you ask? I let you think on that and see if you can come up with a reason.

So, back to our discussion, it's obvious that you need one more level of indirection. All you need to do is to pass that function a pointer to a pointer to T, like this:


void AllocateMemory( unsigned char** ppBuffer ) {
*ppBuffer = new unsigned char[ 100 ];

// As a completely unrelated side note, what does the following code do?
// ppBuffer = new unsigned char *[ 100 ];
}





But then again, you have to dereference that pointer to pointer to unsigned char to access the pointer to unsigned char, which is ugly at best. The solution? Pass a reference to a pointer to T, and again, let the compiler do all the nasty pointer manipulation for you behind the scene.


void AllocateMemory( unsigned char*& pBuffer ) {
pBuffer = new unsigned char[ 100 ];
}



Share this post


Link to post
Share on other sites
Ashkan:
Not only does this answer my question clearly, but you also helped me to solve a problem in a separate program I had written a few weeks ago. I had a situation much like the first memory allocation function you posted.

From this information I gather that using a reference to a pointer is a "preferred" or "cleaner" way of using a pointer to a pointer method...which makes sense. It does however raise some confusion about pointers being passed to functions.

From what I have learned thus far, pointers are variables that hold a memory address. So if I pass a pointer to a function, I'm just passing a memory address...right? If so then using the new construct would return the memory location of the new data and store it in the pointer. However as you noted when the function returns, the pointer that I passed to the function is still in its original state.

So I'm obviously getting something wrong in my thinking. Do I have the definition of a pointer confused, or is there something "different" happening when the pointer is passed to a function as a parameter?

I do appreciate all the answers I am getting, really am learning quite a bit here! :-)

Share this post


Link to post
Share on other sites
Yes, you're right in thinking that a pointer is a variable that holds a memory address. Fundamentally, there's no difference between a pointer to an int, a pointer to a float or a pointer to a custom abstract data type such as a linkedlist. They are all just pointers and as such they are only variables holding memory addresses. A memory address on the other hand is just a discrete integral value. The difference is superficial. This difference is enforced in strongly-typed programming languages, either by the compiler (in a statically type-checked language where type checking is performed during compile time, such as C++) or runtime (in a dynamically type-checked language, where type checking is performed during runtime). Actually type-checking goes well beyond pointers and applies to every data type that you're going to use but that's another discussion.

So, back to our discussion, pointers are just variables and variables are passed by value! Passing a variable by value means that the contents of the variable is copied over. So when we write something like this,


void f( int x ) {
++x;
}

int main() {
y = 0;
f( y );

return 0;
}





The compiler actually generates some code behind your back that copies the contents of y (0 here) into x so it can be accessed by f(). Actually, what's f() is changing at this point is a *copy* of y and not y itself. That's why we need to pass that variable by reference so f() can access the original contents rather than a copy.

So what's this talk about pass-by-reference if all variables are passed by value? There's actually no such thing as passing by reference! Pass-by-reference is *mimiced* by passing a variable that holds the memory address of another variable, but the pointer that's being passed is actually passed by value. So in the following example:


void AllocateMemory( unsigned char* pBuffer ) {
pBuffer = new unsigned char[ 100 ];
}





pBuffer is again a variable, this time holding a memory address, and again is passed by value. What is actually passed by reference is the contents of the buffer (which is none in this example, since pBuffer isn't really pointing anywhere useful. It just holds some garbage value, pointing to some unknown memory location).

Can we directly change the contents of the buffer to which pBuffer points to? Yes. Why? Because we know where it resides in memory. Can we change the contents of the variable that holds the memory address of the beginning of that buffer (i.e. pBuffer itself)? No. Why? Let's see another example before answering this.


void f( int* pX ) {
(*pX)++;
}

int main() {
int y = 0;
f( &y );

return 0;
}





In this example, a variable holding memory address of another variable (AKA a pointer) is passed to f(). The pointer itself is a variable and is passed by value as a result, but this level of indirection **mimics* a pass-by-reference.

So back to our first version of AllocateMemory (shown above), why can't we successfully assign the address of the allocated memory to pBuffer? You got it. Because, pBuffer is a variable and as such is passed by value. What we are actually changing in that function is a *copy* of that pointer not the pointer itself. This copy is useful when we want to access the location where it points to because it makes no difference if we're accessing that memory location via the original pointer or a copy of it, but we can't change the pointer itself because it's a copy. What do we need then? Another level of indirection. So not only can we change the contents of that buffer, but we can also change the contents of that pointer. But can we change the contents of that pointer to pointer to unsigned char? No. Because that's a copy. We can change that, but it has no effect on it's original value. If we want to change that we need yet another level of indirection.

Where do references fit in? References are mostly syntactic sugar. I said mostly because references have some minor differences with pointers, but they're implemented just like regular pointer behind our back.

Hope that helps :)

Share this post


Link to post
Share on other sites
I understand now!

It also makes sense if I go back to my old c++ book that has a lesson on pointers and references. The lessons say that these items allow access to the data without having to make a local copy. What is left out is what is going on with the pointer variable itself, which you explained very well.

Printed, highlighted and thrown in my notes!
Appreciate the help very much! :-)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement