I have a function that takes a pointer as a parameter, this function changes the pointer but when I return from that fuction the pointer is still the same as it was before. Why is that?
int x = 6;
void function( int *n ) // pass in a pointer to an int
{
n = &x; // change the value of the pointer
}
void main ( )
{
int* pa = NULL;
// call the function to change the value of the pointer
function( pa );
// this doesn't work pa = NULL
if( pa )
cout << "Value of pa is " << *pa << endl;
}
I noticed that if I change the definition of function to void function( int *&n ) then it works the way I intend.
willchop
September 5th, 2002, 09:58 AM
Try:
void function( int **n )
{
*n = &x;
}
In your original code you are passing your pointer by value.
You need to pass by reference (a pointer to your pointer).
regards, willchop
jfaust
September 5th, 2002, 10:16 AM
To change the value of a pointer, you need to pass the address of that pointer, as willchop showed with a pointer to a pointer.
You need to pass by reference (a pointer to your pointer).
These are two separate things.
I noticed that if I change the definition of function to void function( int *&n ) then it works the way I intend.
Pointer to pointer (int**) is better than pointer to reference (*&) because it's more obvious what's happening and not nearly as ugly.
Jeff
CallMeJoe
September 5th, 2002, 11:17 AM
One advantage of using *& is that it ensures a valid value has been passed (vs. a NULL)
jflegert
September 5th, 2002, 01:28 PM
Pointer to pointer (int**) is better than pointer to reference (*&) because it's more obvious what's happening and not nearly as ugly.
I guess it's a matter of preference. I prefer references myself. Which is uglier:
(*p)++; // using the pointer to pointer
or
p++; // using the pointer reference
Maybe your argument/opinion would be more compelling if you said "safer".
Just my opinion,
John Flegert
jfaust
September 5th, 2002, 02:06 PM
Ya, I meant safer--more obvious to the developer what is expected. I avoid non-const references in favor of pointers.
But I still think *& is confusing and ugly.
Jeff
mce
September 6th, 2002, 12:34 AM
will &* achieve the same thing as *&?
Graham
September 6th, 2002, 03:31 AM
No. I'm not sure that "&*" is even legal. If it is, it's almost certainly equivalent to plain "*".
Graham
September 6th, 2002, 03:46 AM
BTW: I have to disagree with Jeff on one point. Pointer-to-pointer is not more obvious than reference-to-pointer. Pointer-to-pointer has multiple interpretations (2D-array for example), so it's not always obvious that it means that a value may be returned.
void foo(int ** i) // will it change "i", or does it expect a 2D array of int?
{
*i = new int[10]; // Ahhh, it's changing "i".
}
int main()
{
foo(0); // Oh, b*gger!
}
Interestingly, I had to think twice about the (single) statement in the body of foo()
Compare:
void foo(int *& i) // Mmmm - reference to non-const, "i" could be modified.
{
i = new int[10]; // And so it is.
}
int main()
{
foo(0); // DING! Compilation error.
}
As John said, it's a matter of preference, and I find that using a pointer rather than a reference to non-const is particularly ugly. (And I keep having to think 'do I need to put "*" in front or not?')
I would go so far as to say that "reference to non-const" is idiomatic for "this variable will have its value changed by this function". Pointer to non-const doesn't have that idiomatic meaning - it's ambiguous.
PaulWendt
September 6th, 2002, 06:21 AM
Graham said:
As John said, it's a matter of preference, and I find that using a pointer rather than a reference to non-const is particularly ugly. (And I keep having to think 'do I need to put "*" in front or not?')
I LIKE the ugliness; I like how a person looking at client code
can easily see if it's possible that a value can be modified without
having to look up the function in particular. The & doesn't
always mean that the variable will be modified, of course, but just
that the possibility is there.
With the double-pointer thing, you definitely have a point there.
I'm always looking for new ways to do things anyway so I like
coming on this board and finding other peoples' viewpoints.
Now all this thread needs is for someone to come and tell
everyone how they'd fail at a C++ job interview :)
--Paul
Graham
September 6th, 2002, 08:44 AM
Originally posted by PaulWendt
... The & doesn't always mean that the variable will be modified, of course, but just that the possibility is there. ...
--Paul
The same is true of the "*". What's important is the reference (or pointer) to non-const - if you're not going to change it, you'd make it a reference (or pointer) to const.
Also consider this:
void foo(MyClass*);
void bar(MyClass&);
Now, in both cases, the argument passed could be a derivative of MyClass. I would argue, however, that most people would tend not to assume that bar() relied on polymorphic behaviour - indeed, they would probably be surprised to discover that it did. Tell someone that foo() relies on polymorphic behaviour and they won't bat an eyelid. OK, maybe that's simplistic, and I don't want to get involved in a religious war here - if you prefer pointers to references, I ain't gonna stop you - I just want to present my arguments why I prefer references for the consideration of those who maybe haven't made their minds up yet.
I prefer to use reference to non-const idiomatically to mean "this argument will (probably) be modified". I can't impose that meaning on a pointer to non-const because it has too many other, well-established, meanings (pointer to array [that might be modified]; pointer to polymorphic object [that might be modified]; pointer to heap object [that might be modified], etc). Admittedly, the distinction is subtle, but I try to be consistent with it.
PaulWendt
September 6th, 2002, 08:48 AM
Hi, Graham.
I don't dispute anything you said, but I was actually meaning
something like this:
callSomeFunction(&variableToBeModified);
I think that the & makes it clearer that the variable can possibly
be modified ... without bothering to look at the function's
documentation [wherever it may be]. Granted, you'll want to look
at documentation anyway, but at first glance, I like the ugliness
of the pointer syntax better. I think I'm in the minority in this :)
--Paul
jfaust
September 6th, 2002, 09:05 AM
Another option, just to bring it up.
Pointer to pointer (or reference) is used primarily to return memory allocated in the method to the caller. A better way would be to have it as the return value of the method using transfer-of-ownership with a smart pointer such as std::auto_ptr or boost::shared_ptr.
This removes ambiguities and ugliness of ** and the clumsiness of *&, as well as removing the responsibility of deallocating the memory from both the caller and the allocater.
Jeff
CallMeJoe
September 6th, 2002, 09:20 AM
Jeff stated:
Pointer to pointer (or reference) is used primarily to return memory allocated in the method to the caller.
I actually rarely use it this way. Recently I wrote a parsing algorithm where all the sub-functions took a const pointer-to-reference (const char *& pStr).
However, IF you are allocating memory in this function and the function is more than trivial, Jeff's point should be considered. (I'm not a big fan of "smart pointers" and rarely use them.)
jfaust
September 6th, 2002, 09:37 AM
references and const references have very different meaning. I just want to clarify I was talking about non-const references.
I have to admit, I've rarely used smart pointers until recently. I have an object passed around a lot and the ownership of this object is far from obvious. I started down the path of reference counting it, where every user of the object addrefs and releases. Then I came across boost::smart_ptr, which handles the reference counting internally and deletes itself when it's no longer in use. It's really quite remarkable. It's fast, transparent, safe, and deallocates memory correctly. Most important, it removes the responsiblity of reference counting from the client, which can be an annoying source of bugs.
boost::smart_ptr can also safely be used in STL containers, while std::auto_ptr cannot.
Jeff
AnthonyMai
September 6th, 2002, 09:41 AM
Pointer-to-pointer has multiple interpretations (2D-array for example), so it's not always obvious that it means that a value may be returned.
That is not right. Pointer-to-pointer is totally a different thing from a 2-D array or a pointer to a 2-D array. Try casting a pointer to a 2D array to a pointer-to-pointer. You CAN'T. Even in the case of 1D, you may cast a pointer to a 1D array to a pointer, it is still worth pointing out that pointer and 1D array are DIFFERENT things. Any one failing to see that should fail a job interview.
a[0] may or may not be valid depending how a is declared. If a is an array, then it is valid. If a is a pointer, a[0] may not be valid.
A pointer-to-pointer has only ONE possible interpretation:
Step1.Use this pointer-to-pointer, suppose it point to a valid address (The pointer-to-pointer is neither NULL nor point to invalid address), you may fetch (or store back) a pointer.
Step2.Use the pointer fetched in step1, suppose it is a valid pointer, (The pointer value is neither NULL nor point to invalid address) You can fetch (or store back) a value of the type. If there is a const modifier before the pointer-to-pointer declaration (const int ** mypp;), then you can noly fetch but not store back.
Nothing in the pointer-to-pointer implies any thing that may be an array. Actually to access elements in a 2D array you follow different steps:
1.take the x and y index of the element and use them to calculate an index. (index = y*X_DIMENTION + x)
2.Use the index to and treat the 2D array like 1-D array to fetch the value.
For example:
int a[16][16];
int b = a[1][2];
is actually implemented something like this 1D array:
int a[16 * 16];
int b = a[1*16 + 2];
willchop
September 6th, 2002, 10:03 AM
A better way would be to have it as the return value of the method using transfer-of-ownership with a smart pointer such as std::auto_ptr or boost::shared_ptr.
Very good point. Returning a pointer to, or reference to a generic
scoped automatic variable can be disastrous if the programmer
isn't familiar with the code structure.
as well as removing the responsibility of deallocating the memory from both the caller and the allocater.
Another good point. We can get around scoping problems with
automatic variables by returning pointer to, or reference to
dynamically created variables. Although this leads the
forementioned problem: who is responsible for deallocating the
variable? Using smart pointers is clearly an improvement. The
notion of things like ownership and reference counting when
dealing with pointers is what makes our code much more robust
and less error prone.
Edit: Of course, returning variable by value is also safe.
regards, willchop
PaulWendt
September 6th, 2002, 12:15 PM
Originally posted by AnthonyMai:
Any one failing to see that should fail a job interview.
Ask and ye shall receive.
--Paul
PaulWendt
September 6th, 2002, 12:19 PM
Originally posted by AnthonyMai
That is not right. Pointer-to-pointer is totally a different thing from a 2-D array or a pointer to a 2-D array. Try casting a pointer to a 2D array to a pointer-to-pointer. You CAN'T. Even in the case of 1D, you may cast a pointer to a 1D array to a pointer, it is still worth pointing out that pointer and 1D array are DIFFERENT things. Any one failing to see that should fail a job interview.
You're arguing irrelevant semantics here; the main point Graham
was trying to make was:
so it's not always obvious that it means that a value may be returned.
--Paul
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.