C++: difference between ampersand "&" and asterisk "*" in function/method declaration?

Is there some kind of subtle difference between those:

void a1(float &b) {
b=1;
};
a1(b);

and

void a1(float *b) {
(*b)=1;
};
a1(&b);

?

They both do the same (or so it seems from main() ), but the first one is obviously shorter, however most of the code I see uses second notation. Is there a difference? Maybe in case it's some object instead of float?

75260 次浏览

Both do the same, but one uses references and one uses pointers.

See my answer here for a comprehensive list of all the differences.

In the first example with references, you know that b can't be NULL. With the pointer example, b might be the NULL pointer.

However, note that it is possible to pass a NULL object through a reference, but it's awkward and the called procedure can assume it's an error to have done so:

a1(*(float *)NULL);

In the second example the caller has to prefix the variable name with '&' to pass the address of the variable.

This may be an advantage - the caller cannot inadvertently modify a variable by passing it as a reference when they thought they were passing by value.

Functionally in your example, both versions do the same.

The first has the advantage that it's transparent on the call-side. Imagine how it would look for an operator:

cin >> &x;

And how it looks ugly for a swap invocation

swap(&a, &b);

You want to swap a and b. And it looks much better than when you first have to take the address. Incidentally, bjarne stroustrup writes that the major reason for references was the transparency that was added at the call side - especially for operators. Also see how it's not obvious anymore whether the following

&a + 10

Would add 10 to the content of a, calling the operator+ of it, or whether it adds 10 to a temporary pointer to a. Add that to the impossibility that you cannot overload operators for only builtin operands (like a pointer and an integer). References make this crystal clear.

Pointers are useful if you want to be able to put a "null":

a1(0);

Then in a1 the method can compare the pointer with 0 and see whether the pointer points to any object.

Aside from syntactic sugar, the only real difference is the ability for a function parameter that is a pointer to be null. So the pointer version can be more expressive if it handles the null case properly. The null case can also have some special meaning attached to it. The reference version can only operate on values of the type specified without a null capability.

Yes. The * notation says that what's being pass on the stack is a pointer, ie, address of something. The & says it's a reference. The effect is similar but not identical:

Let's take two cases:

   void examP(int* ip);
void examR(int& i);


int i;

If I call examP, I write

   examP(&i);

which takes the address of the item and passes it on the stack. If I call examR,

   examR(i);

I don't need it; now the compiler "somehow" passes a reference -- which practically means it gets and passes the address of i. On the code side, then

   void examP(int* ip){
*ip += 1;
}

I have to make sure to dereference the pointer. ip += 1 does something very different.

   void examR(int& i){
i += 1;
}

always updates the value of i.

For more to think about, read up on "call by reference" versus "call by value". The & notion gives C++ call by reference.

One big difference worth noting is what's going on outside, you either have:

a1(something);

or:

a1(&something);

I like to pass arguments by reference (always a const one :) ) when they are not modified in the function/method (and then you can also pass automatic/temporary objects inside) and pass them by pointer to signify and alert the user/reader of the code calling the method that the argument may and probably is intentionally modified inside.