C++
In C++, you can pass by reference, and you do that when you want modifications of the parameter to affect the argument which the caller passed in. That is, passing by reference represents an out or in/out parameter.
You pass a pointer if the function wants a pointer (obviously), or if you want to signify an optional output parameter - since a reference always has to bind to something, but a pointer can be null.
By the same logic, pass a pointer to pointer if the function actually needs double pointers (very rare in C++) or if you want to signify an optional [in-]out parameter of pointer type (also quite rare).
Here are some examples (contrived, but should demonstrate the thing):
int square(int x) //pass int by value
{ return x * x; }
void squareRoots(double in, double &plus, double &minus) //pass double by reference
{
plus = sqrt(in);
minus = -plus;
}
int toNumber(String s, bool *ok = nullptr) //optional out parameter
{
try {
int val = s.toNumber();
if (ok)
*ok = true;
return val;
} catch (NotANumber &) {
if (ok)
*ok = false;
return 0;
}
}
int computeAge(Person *person) //pass pointer by value
{
if (!person)
return -1;
else
return now() - person->dateOfBirth();
}
bool createPerson(Person * &person) //pass pointer by reference
{
if (tooManyPeople())
return false;
person = new Person();
return true;
}
int sum(int **values) //pass double pointer by value
{
if (!values)
return 0;
int res = 0;
while (*values) {
res += **values;
++values;
}
return res;
}
bool allocate(int ** &arr) //pass double pointer by reference
{
if (!enoughMemory())
return false;
arr = new int*[1024]; // array of 1024 pointers to int
return true;
}
bool newNode(Node **node = nullptr) //optional out parameter
{
Node *added = dataStructure.createNode();
if (node)
*node = added;
return added;
}
(Note 1: I am only talking about non-const references here, since that's relevant to the pass by pointer vs. pass by reference. Passing by const-reference usually means "the object is too big to copy needlessly," and does not apply really when pointers to pointers could be involved).
(Note 2: The above examples are horrible in that they use owning raw pointers, dynamic array allocation etc. In actual C++, you would use smart pointers, std::vector
etc. instead. That's why pointers to pointer are rare in C++).
C
In C, double pointers are more common, since C does not have a reference type. Therefore, you also use a pointer to "pass by reference." Where &
is used in a parameter type in the C++ examples above, *
would be used in C (and dereferenced when manipulating the parameter). One example:
void squareRoots(double in, double *plus, double *minus) //pass double "by reference"
{
*plus = sqrt(in);
*minus = -*plus;
}