Going backwards, assuming:
Code:
int a = 5;
int b = 2;
int *pointer;
int **dpointer;
There's nothing all that mysterious about dpointer. The only real difference in the concept between dpointer and pointer is that where pointer may point to the address of a variable, dpointer points to the address of a pointer. One could argue that dpointer is that singularly special case where the type it points to happens to be a pointer, whereas pointer does not.
That is, where
Code:
pointer = &a
or
pointer = &b
This does the same kind of thing
Code:
dpointer = &pointer
with the only real exception being that pointer is a pointer, not an integer (or whatever type the pointer is declared to point to).
This means that whatever can be done with a or b can be done with *pointer:
Code:
//where
pointer = &a;
a = 6;
*pointer = 6;
Likewise, whatever can be done with pointer can be done with *dpointer
Code:
//where
pointer = &a;
dpointer = &pointer;
*pointer = 8; // which is the same as a = 8;
**dpointer = 8; // same as *pointer = 8
*(*dpointer) = 8; // think of it this way, where *dpointer is the same as pointer
When used in assignments (not declarations), you can read "*pointer" as: what's stored at pointer.
Now, to your questions:
#1: Yes, a pointer stores the address of something, in this case an integer, such that the "&a" gives the pointer to where a is stored, and pointer = &a copies the address of a to the pointer.
#2: You've written the statement incorrectly. dpointer can't accept *pointer, *pointer is read in this context as "what's stored at" pointer. dpointer is not declared to take that type (it is an integer), dpointer is declared to take the address of a pointer (a double pointer does that). The correct fashion for this example question should be dpointer = &pointer; meaning that dpointer, which is declared to accept the address of a pointer, is assigned to the address of pointer.
#3 If we assume dpointer is correctly assigned to the address of a pointer, as in dpointer = &pointer, we have to qualify this with one important point: we must know that pointer is also valid to use this, so let's assume, for simplicity, that:
Code:
int a = 5;
int b = 2;
int *pointer;
int **dpointer;
pointer = &a; // pointer is now valid to use
dpointer = &pointer; // dpointer is valid to use
//b = *dpointer; // this is an error and won't compile (usually)
b = **dpointer;
b = *pointer; // this is the same as **dpointer
b is an integer. It can be assigned to another integer, copying the value, as in b = a;
pointer points to an integer, and if assigned as above, what's stored at that pointer is an integer, so b = *pointer;
dpointer points to the address of a pointer to an integer, so what's stored at dpointer is a pointer to an integer. Think of that this way:
Here, dpointer is 'dereferenced' inside the parenthesis. Since dpointer is a pointer to a pointer, what is stored at dpointer is a pointer.
That isn't an integer, is a pointer to an integer. To get the integer, it must be dereferenced again, because what "comes out of" of the parenthesis is a pointer, it's just like "pointer", so
Code:
* (*dpointer);
//is the same as
*pointer;
So,
Code:
int a = 5;
int b = 4;
int *pointer = &a;
int **dpointer = &pointer;
**dpointer = 4; // a is now 4
if ( *pointer == b ) // is true
Now, in closing, this is a crash:
Code:
int a = 5;
int b = 4;
int *pointer = NULL;
int **dpointer = &pointer; // this is ok but be warned what's next
**dpointer = 3; // this crashes because pointer itself is NULL.
*dpointer = &a; // this does the same as pointer = &a
**dpointer = 2; // this would work if it hadn't crashed above