Louis said:
In my case passing pointer variable to function is the best using a
pointer reference or a raw pointer?
It depends.
You seen, pointers and references are low level constructs.
There are several different parameter passing modes, that can be
explained in a higher level way:
- input parameters: The argument may be an expression (r-value).
Assigning to the parameter, inside the function,
has only a local effect, the value of the
expression cannot be changed.
- output parameters: The argument cannot be an expression (r-value),
only a place (l-value). The old value in that
place is not used, the function stores a new
value there.
Assigning to the parameter, inside the function,
will change the value of the argument place.
- inout parameters: The argument cannot be an expression (r-value),
only a place (l-value). The old value is used by
the function, and may be modified by the
function.
Assigning to the parameter, inside the function,
will change the value of the argument place.
When programming, you should first be concerned only by these
considerations.
Then, there are different mechanisms by which these parameter passing
modes may be implemented:
- argument passing by copy: the data is copied from the argument
to the parameter (input), or from the
parameter to the argument (output).
- argument passing by reference: a pointer to the data is copied from
the argument to the parameter
(input); the argument data is
accessed by dereferencing the pointer
parameter, and can thus be modified
(output).
- argument passing by name: this is a complex parameter passing
mechanisms that was used in some
early languages such as
Algol. Basically, the name of the
argument variable was in some way
passed to the parameter, and then
when using the parameter, it would
find the place by indexing the name
in the symbol table.
- etc.
In the case of C, the only mechanism is argument passing by copy. All
the arguments are expressions that are evaluated and whose value is
copied to the parameter.
Implementing an input parameter is therefore straigtforward, it's what
is normally done.
(CI)
void f(int inputParameter){ assert(inputParameter==42); inputParameter=0; }
f(24*2);
int i=42; f(i); assert(i==42);
int a[]={3,42,3}; f(a[1]); assert(a[1]==42);
To implement an inout parameter, we must use a pointer to the place:
C(IO)
void f(int* inoutParameter){ assert((*inoutParameter)==42); (*inputParameter)=0; }
f(&(24*2)); // ERROR! we cannot take a pointer of an expression.
int i=42; f(&(i)); assert(i==0);
int a[]={3,42,3}; f(&(a[1])); assert(a[1]==0);
To implement an output parameter, we must use a pointer to the place,
just like for an inout parameter, but we do not read the value of the
place in the function, before setting it:
C(O)
void f(int* outputParameter){ (*outputParameter)=0; }
f(&(24*2)); // ERROR! we cannot take a pointer of an expression.
int i; f(&(i)); assert(i==0);
int a[3]; f(&(a[1])); assert(a[1]==0);
However, in C there is a strange treatment of arrays: they're
considered as pointer to the first element when passed as arguments.
And old versions of the language could not copy structure arguments
(at least beyond a certain size) either. Also, considerations of
performance will make you seek another mechanism to pass big arguments.
For these cases, an input parameter can still be passed using a pointer:
void f(const int* inputParameter,int size){
if(1<size){
process(inputParameter[1]);
}
}
In modern C can also be written as:
void f(const int inputParameter[],int size){
if(1<size){
process(inputParameter[1]);
}
}
int a[]={1,2,3}; f(a,sizeof(a)/sizeof(a[0]));
/* equivalent to: */ f(&(a[0]),sizeof(a)/sizeof(a[0]));
For an inout or output array parameter, we would just drop the 'const'.
Now, in C++ we have in addition the references, and argument passing
by reference. We can use it to implement inout and output parameters:
Implementing an input parameter is the same as in C:
C++(I)
void f(int inputParameter){ assert(inputParameter==42); inputParameter=0; }
f(24*2);
int i=42; f(i); assert(i==42);
int a[]={3,42,3}; f(a[1]); assert(a[1]==42);
To implement an inout parameter, we may use a reference to the place:
C++(IO)
void f(int& inoutParameter){ assert(inoutParameter==42); inputParameter=0; }
f(24*2); // ERROR! we cannot take a refernece of an expression.
int i=42; f(i); assert(i==0);
int a[]={3,42,3}; f(a[1]); assert(a[1]==0);
To implement an output parameter, we must use a pointer to the place,
just like for an inout parameter, but we do not read the value of the
place in the function, before setting it:
C++(O)
void f(int& outputParameter){ outputParameter=0; }
f(24*2); // ERROR! we cannot take a pointer of an expression.
int i; f(i); assert(i==0);
int a[3]; f(a[1]); assert(a[1]==0);
In C++, we still have the same problem with array, that are passed by
copy of a pointer to the first element by default, but we can now use
passing by reference:
typedef int Vector[3];
void f(const vector& inputParameter){
assert(inputParameter[1]==2);
inputParameter[1]=0;
}
int a[]={1,2,3}; f(a); assert(a[1]==0);
(and drop 'const' for inout and output parameters).
For structures there's no more size restriction for passing by copy,
but you might still want to use a reference there, to avoid copying
big structures.
In the case of a structure such as std::vector<int>, you may pass it
by copy, since it's really a small structure (usually 3 words), and
passing this structure by copy won't copy the elements in the vector.
A last word, compare the call sites in C++(I) and C++(IO) above:
int i=42; f(i); assert(i==42);
int i=42; f(i); assert(i==0);
It may look surprizing that in one case i is not changed (and couldn't
be changed), while in the other case, i can be changed. When reading
the call site alone, no syntax clues us about this difference. For
this reason, some C++ programmers prefer to keep using pointers for
inout and output parameters, see C(IO):
int i=42; f(&(i)); assert(i==0);
My own point of view is that (1) the name of the function should clue
you:
int salary=42; setSalary(salary); assert(salary==42);
int taxes; getTaxes(taxes); assert(taxes==0);
so that you can still use references, without any loss of readability,
and (2) you should avoid using inout and output parameters anyways,
and rather use a functional programming style, where you have only
input parameter and use results:
int salary=42; setSalary(salary); assert(salary==42);
int taxes; taxes=getTaxes(); assert(taxes==0);
In my case passing pointer variable to function is the best using a
pointer reference or a raw pointer?
So to answer your questions, it depends on whether the parameter is an
input, inout or output parameter. A pointer is small (one word), so
as an input parameter you can pass it by copy:
typedef int* intp;
void f(intp inputParameter);
int i=42; f(&i);
intp p=&i; f(p); assert(p==&i);
In the case of an inout or output parameter, if you choose to have a
call place hint that your pointer may be modified, you'd use a pointer
to the pointer:
typedef int* intp;
int k=24;
void f(intp* outputParameter){ (*outputParameter)=&k; }
intp p=0; f(&p); assert(p==&k);
If you choose better function names, you can use a reference:
typedef int* intp;
int k=24;
void getPointerToIntStorage(intp& outputParameter){ outputParameter=&k; }
intp p=0; getPointerToIntStorage(p); assert(p==&k);
still a bit confuse
do u mean using raw pointer, temp will modify the same address where d
pointing to?
while using pointer reference, temp will modify the reference of d...?
What I mean here is that take_a_raw_pointer takes a r-value
(expressions), while take_a_pointer_reference takes a l-value
(places).