views:

286

answers:

5

Dear all,

I have been told by my colleague that this is used like an out parameter in C#, can some precisely explain how? I get the idea, but there is something that is missing.. I know that if we pass the pointer itself p to foo (*p), and the function body does p = new int(), we might have a dangling modifier! what I don't get is how foo(**p) avoids something like that from happening !

Thanks

A: 

Using a **p you can change what *p refers to in another part of your program and the function still works on the right p.

Gabb0
+10  A: 
void foo(int** p)
{
 *p = new int;
}


void main()
{
 int *p = NULL;

foo(&p);
//unless you pass the pointer to p, the memory allocated in the 
//function foo is not available here.

foo(p); // lets assume foo is foo(int* p)

//when you pass only pointer p to `foo()` then the value of the pointer will be 
//passed ( pass by value) to foo() and hence, any modification to pointer p ( in
// the form of allocating memory also) will not be available after the
// control returns from foo()
// The p will still points to NULL here, not the memory allocated in foo().  

}
aJ
or we can pass modify the signature of foo to take the reference to the pointer.
Naveen
+1  A: 

Pointer-to-pointer... somewhat obfuscated for: passing a pointer by reference. Using a typedef greatly simplifies things:

typedef int* SomeType;

// C-style output parameter: pass address of variable
void create( SomeType* aVariable ) {
   *aVariable = new int;
}

// easier, more idiomatic C++: pass variable by reference
void create2( SomeType& aVariable ) {
   aVariable = new int;
}

int main() {
   SomeType localVar;
   create( &localVar );
   create2( localVar );
}
xtofl
Mustafa A. Jabbar
You cannot put an `int` pointer into the dereferenced `localVar`: `*localVar` is an `int`.
xtofl
+3  A: 

int **p is not a 2D array. It is a pointer to a pointer to an integer.

Daniel Daranas
but it can be treated as a 2 d array .. to create a 2 X 2 array you might do something like int **p = new *int[2];*p[0] = new int[2]; *p[1] = new int[2];
Mustafa A. Jabbar
@Mustafa: In which case, the memory is still not organized as a 2D array but rather it's a pointer to a 1D array of "row" pointers that each point to a separate 1D array of integers. There are several non-obvious differences youu must be careful of here when you treat them as 2D arrays: 1) The "rows" do not have to be contiguous (i.e. you can't add a row width to get the next row). 2) The "rows" do not have to be the same size (they can vary in number of accessible elements).
Adisak
+3  A: 

Others have explained what void foo(int **p) does but they didn't answer another part of your question: the "when the parameter is not meant to be a 2D array".

The answer here is the parameter int**p is NEVER a 2D array. Even if you dereference it as p[row][column] there are a couple major differences:

1) The memory is not organized as a 2D array but rather it's a pointer to a 1D array of "row" pointers that each point to a separate 1D array of integers (indexed here by "column").

2) The "rows" do not have to be contiguous (i.e. you can't add a row width to get the next row).

3) The "rows" do not have to be the same size (they can vary in number of accessible elements)

To pass a 2D array to a function you can use a variety of function signatures. The easiest is void foo(int p[25][15]) (where 25 and 15 are your array row and column size).

The following function signatures for 2D arrays generate the same code when called as well: void foo(int (&p)[25][15]) and void foo(int (*p)[25][15]) and void foo(int p[][15]). The last version here p[][15] allows you to handle 2D arrays with a fixed column width but a varying number of rows.

At the risk of being too "clever", you can pass a 2D array as void foo2(int *p) if you pass the address of the first element (or you can use int a[25][15]; foo2(a[0]);). However, in foo2, you will have to use pointer math to access the rows and columns of the 2D array and you will also have to change the way you call the function (to pass an int * rather than an array pointer). This "clever" technique is occasionally useful in C when you have to handle 2D arrays of varying dimension sizes. In C++, it is easier to just use a template with the array sizes as template parameters to handle 2D arrays of various sizes.

Adisak
+1.. Thanks for bringing my attention to these important points..
Mustafa A. Jabbar
Adisak
GREAT .. if only I could find a hack to vote this up a 100 times
Mustafa A. Jabbar
I wonder if the person who downvoted this answer could explain why they did so?
Adisak