Passing an Array by reference in C - c

I'm new to C and I have a doubt.
Since C functions create local copies of it's arguments, I'm wondering why the following code works as expected:
void function(int array[]){
array[0] = 4;
array[1] = 5;
array[2] = 6;
}
int main(){
int array[] = {1,2,3};
function(array);
printf("%d %d %d",array[0],array[1],array[2]);
return 0;
}
With the line output being 4 5 6.
Why does this work while the following doesn't?
void function(int integer){
integer = 2;
}
int main(){
int integer = 1;
function(integer);
printf("%d",integer);
return 0;
}
The output is just 1 in this case.
Short version: Why can functions modify the values of their parent variables if they are passed as array?
Thank you all!

This is caused by the fact that arrays tend to decay into pointers.
int a[] = { 1, 2, 3 };
int* p = a; // valid: p is now the address of a[0]
a = p; // NOT valid.
printf("a = %p\n", a);
printf("p = %p\n", p); // prints same address as a
a and p will print the same value.
Contrary to what others have said, a is not a pointer, it can simply decay to one. http://c-faq.com/aryptr/aryptrequiv.html
In your first function() what gets passed is the address of the array's first element, and the function body dereferences that. Infact, the compiler is treating the function prototype as this:
void function(int* array /*you wrote int array[]*/){
array[0] = 4;
array[1] = 5;
array[2] = 6;
}
function(&array[0]);
This has to happen because you said "array of unknown size" (int array[]). The compiler could not guarantee to deduce the amount of stack required to pass by value, so it decays to a pointer.
---- Edit ----
Lets combine both your examples and use more distinctive names to make things clearer.
#include <stdio.h>
void func1(int dynArray[]) {
printf("func1: dynArray = %p, &dynArray[0] = %p, dynArray[0] = %d\n",
dynArray, &dynArray[0], dynArray[0]);
}
void func2(int* intPtr) {
printf("func2: intPtr = %p, &intPtr[0] = %p, intPtr[0] = %d\n",
intPtr, &intPtr[0], intPtr[0]);
}
void func3(int intVal) {
printf("func3: intVal = %d, &intValue = %p\n",
intVal, &intVal);
}
int main() {
int mainArray[3] = { 1, 2, 3 };
int mainInt = 10;
printf("mainArray = %p, &mainArray[0] = %p, mainArray[0] = %d\n",
mainArray, &mainArray, mainArray[0]);
func1(mainArray);
func2(mainArray);
printf("mainInt = %d, &mainInt = %p\n",
mainInt, &mainInt);
func3(mainInt);
return 0;
}
Live demo at ideone: http://ideone.com/P8C1f4
mainArray = 0xbf806ad4, &mainArray[0] = 0xbf806ad4, mainArray[0] = 1
func1: dynArray = 0xbf806ad4, &dynArray[0] = 0xbf806ad4, dynArray[0] = 1
func2: intPtr = 0xbf806ad4, &intPtr[0] = 0xbf806ad4, intPtr[0] = 1
mainInt = 10, &mainInt = 0xbf806acc
func3: intVal = 10, &intValue = 0xbf806ad0
In func1 and func2 "dynArray" and "intPtr" are local variables, but they are pointer variables into which they receive the address of "mainArray" from main.
This behavior is specific to arrays. If you were to put the array inside a struct, then you would be able to pass it by value.

An array passed to a function is converted to a pointer. When you pass a pointer as argument to a function, you simply give the address of the variable in the memory. So when you modify the value of the cell of the array, you edit the value under the address given to the function.
When you pass a simple integer to a function, the integer is copied in the stack, when you modify the integer within the function, you modify the copy of the integer, not the original.
Reminder of the different kinds of memory in C
In C, we can use three types of memory :
the stack, used for local variables and functions calls: when we create a variable in main(), we use the stack to store the variable, and when a function is called, the parameters given to the method are register in the stack. When we exit a function, we "pop" these parameters to return to the original state, with the used variable before the call of the function. (anecdote: a stackoverflow is when we hack the stack to use previous variables in a function without passing it as parameters)
the heap which corresponds to the dynamicly allocated memory: when we need large amount of data, we use this heap because the stack is limited to a few megabytes.
the code where the program instructions are stored
In the case of this array passed by a function, which is a pointer (address to an other variable), it is stored in the stack, when we call the function, we copy the pointer in the stack.
In the case of the integer, it is also stored in the stack, when we call the function, we copy the integer.
If we want to modify the integer, we can pass the address of the integer to modify the value under the pointer, like this:
void function(int *integer)
{
*integer = 2;
}
int main()
{
int integer = 1;
function(&integer);
printf("%d", integer);
return 0;
}

There is a difference between 'pass by reference' and 'pass by value'
Pass by reference leads to a location in the memory where pass by value passes the value directly, an array variable is always an refference, so it points to a location in the memory. Integers will pass by value by default

In the first code, you are passing the address of the array pointing to the top element in the array. So, when you modify the value in the function and return to the main function you are still accessing the same array which is in the same address. This is called pass by reference.
However, in the second case, the value of the integer is copied from the main function to the called function. In other words, the two integers are in different address in the memory. So modifying one does not modify the other.

The array name is a pointer to the first element in the array. In the first code sample you have passed a pointer to the memory location containing the first array element. In the second code sample you have passed an integer by value so it has nothing to do with the local variable named "integer"
check that link
Pass by reference and pass by value
Pass by Reference / Value in C++

Related

In the following program the invocation of change_it() seems to have no effect. Please explain and correct the code? [duplicate]

This question already has answers here:
How to change a variable in a calling function from a called function? [duplicate]
(3 answers)
Closed 4 years ago.
void change_it(int[]);
int main()
{
int a[5],*p=1;
void change_it(int[]);
printf("p has the value %u \n",(int)p);
change_it(a);
p=a;
printf("p has the value %u \n",(int)p);
return 0;
}
void change_it(int[]) {
int i=777, *q=&i;
a = q; // a is assigned a different value
}
For starters, when you initialize p, you're giving a pointer the value of 1, when it needs a memory location. NULL uses 0, but that doesn't mean you can -or should- just assign integer values to pointers.
Just as an fyi, you can cast the value of 1 like this:
int a[5], *p = (int *) 1;
There's like -2 reasons for doing this, though, the -1th reason being that the minimal type safety that C provides should be respected, and the -2th being that it makes the code hard to understand for other people.
I'm going to assume what you meant to do was not declare a pointer with an address value of 1 though, and say you meant to declare a pointer that holds a value of 1. Unless you have another variable that holds the value of 1 already, you're going to have to first dynamically allocate the pointer, then set its value.
int* p = malloc(sizeof(int));
*p = 1;
If you had another variable to use, you could instead create the pointer on the stack rather than dynamically allocating it, like this:
int* q;
q = p;
Now, calling the same print function on both would yield this:
printf("p has the value %d\n", *p);
printf("q has the value %d\n", *q);
Output:
p has the value 1
q has the value 1
Addressing your main problem, you need to name the parameter in the change_it function, for example:
void change_it(int arr[])
Your program needs the parameter to be named, otherwise it has no idea of knowing you're trying to reference the array. The a variable you reference in the function is not bound to anything; the compiler will know be able to deduce what you're talking about.
Also, you don't need to redeclare the function prototype in your main function. The reason this is not a compiler error is that you can have as many declarations as you want, but only one definition. Again though, there's no reason to do this.
Another fyi, you don't have to name the parameters in your function prototypes, but it's good practice to both name them and be consistent with the names between the prototypes and the actual implementations so that people reading your code understand what's going on.
Also, you're using the %u specifier for the printf function, when you're not actually using unsigned decimal numbers. You're using signed decimals so you should use %d.
Lastly, your change_it function commits one crucial error preventing it from correctly changing the value of the passed-in array properly: you're setting the array that you passed in to the value of q.
Look at the function in your original code closely (pretend you named the input array a, as it looks like you mean to). You first declare an integer variable i and set its value to 777. Then, you create an integer-pointer variable q on the stack and correctly set its value to i. Note: You're not setting q to the value of i, but rather the address of i.
Why does this small but significant distinction matter? When you set a to q in the next line, you're changing the address of the array, specifically the first element of a five-element integer array, to point to the address of an integer variable. This is bad for a few reasons. First, the array is five integers long, but now it points to a single element. If and when you try to access elements 2-5, you'll get either meaningless garbage or a segmentation fault for trying to access memory you don't own. Even worse, the variable i is allocated on the stack, so when the function change_it exists, the function's data will be popped off the stack, and trying to access the address of i will yield either garbage or a segmentation fault for trying to access memory you don't own. See a pattern?
I'm not really sure how to correct this code, as I'm not sure what you were trying to accomplish, but correcting the aforementioned errors, your code now looks something like this:
#include <stdio.h>
void change_it(int arr[]);
int main()
{
int a[5];
int *p = a; // Equivalent to int *p = &a[0];
printf("a address: %p\n", a); // Should be equal to p
printf("p address: %p\n", p); // Should be equal to a
a[0] = 1;
printf("a[0] = %d\n", a[0]); // 1
printf("p has the value %d\n", *p); // 1
change_it(a);
p = a;
printf("a address: %p\n", a);
printf("p address: %p\n", p);
printf("a[0] = %d\n", a[0]);
printf("p has the value %d \n", *p);
return 0;
}
void change_it(int arr[])
{
int i=777;
arr[0] = i;
// Could be just:
// arr[0] = 777;
}
Output:
p address: 0x7fffc951e0b0
a[0] = 1
p has the value 1
a address: 0x7fffc951e0b0
p address: 0x7fffc951e0b0
a[0] = 777
p has the value 777
Note: Your memory address can and probably will be different from these, all it matters is that p and a are equal in both.
Anyways, hope this helps. Let me know if you have any questions.
Alright, you I believe do not have basic understanding of a function: First lets start with declaration and definition:
void change_it(int[]); // THIS IS DECLARATION
int main ()
{
void change_it(int[]); // THIS IS DECLARATION (duplicate and unnecessary
....
}
void change_it(int[] a) // THIS IS DEFINITION
{
int i=777, *q=&i;
a = q; // a is assigned a different value
}
declaration of the function only needs (you can put parameter name for readability) a parameter type, where as definition has to have name of the parameter because in definition parameters are local variables.
printf("p has the value %u \n",(int)p);
This will print the address of p not the value of p. So this should be
printf("p has the value %u \n", *p);
And finally we get to the body of a function. Where you are depending on somthing that have been locally assigned and putting it back into parameters
void change_it(int[] a)
{
int i=777, *q=&i;
a = q; // a is assigned a different value
}
so q is pointer and you are assigning address of local variable i to it. Well what happens when your program exists the function? i might disappear thus loosing its values and its address, which is assigned to q which means q is loosing its variable and value, and which is assigned to a which might loos its variable because it is pointing to i in your function.
This part here:
int a[5],*p=1;
void change_it(int[]); // Here, doesn't compile
printf("p has the value %u \n",(int)p);
That statement isn't just valid, as far as I know, you can't declare a function inside another function in C.
Also:
void change_it(int[]) // Here, an error
{
int i = 777, *q = &i;
a = q;
}
This function needs an argument, but you supplied only its type (being int[]),
void change_it(int a[]) fixes the problem
Your program does not compile and produce warnings. It would not work as you intended.
1) p is a pointer. To access value which it points to you have to dereference it using * dereference opearator.
2)
void change_it(int[]);
is not needed in the body of main.
3)
the invocation of change_it() seems to have no effect
If you want to change a[0] element inside the function change_it name the passing parameter to a and dereference the q pointer,
The working program may look as this:
#include <stdio.h>
void change_it(int a[]);
int main()
{
int a[5] = {0}; // init all element of `a` to `0`
int *p; // declare int pointer
p = a; // p point to array `a`
// print the first element of array `a`
printf("a[0] has the value %d \n",(int)*p);
// call function change_it, pass `a` as the argument
change_it(a);
printf("a[0] has the value %d \n",(int)*p);
return 0;
}
// change the value of the first element of array `a` to 777
void change_it(int a[]) {
int i=777, *q; // declare int i and pointer
q = &i; // pointer `q` points to the `i` now
a[0] = *q; // a[0] is assigned value = 777;
}
Output:
a[0] has the value 0
a[0] has the value 777

Is array as an argument in c really reference type?

#include <stdio.h>
#include <stdlib.h>
void fun(int *arr)
{
arr=(int *)malloc(2*sizeof(int));
arr[0]=5;
arr[1]=4;
printf("in fun {%d, %d}",arr[0],arr[1]);
}
void anotherFunction(int *arr)
{
arr[0]=4;
arr[1]=5;
printf("in fun {%d, %d}",arr[0],arr[1]);
}
int main(void)
{
int *arr,*emptyInMain;
int arr2[]={99,99};
arr=(int *)malloc(2*sizeof(int));
arr[0]=99;
arr[1]=99;
printf("arr ");
fun(arr);
printf("\narr in main {%d, %d}\n",arr[0],arr[1]);
printf("emptyInMain");
fun(emptyInMain);
//printf("\narr in main {%d, %d}\n",emptyInMain[0],emptyInMain[1]); // WILL GIVE RUNTIME ERROR
printf("\n\--commented the line in the code because emptyInMain[0],emptyInMain[1] will give RUNTIME ERROR--");
printf("\narr2");
fun(arr2);
printf("\narr2 in main {%d, %d}\n",arr2[0],arr2[1]);
printf("\nfollowing output shows expected behaviour\n");
printf("\narr2");
anotherFunction(arr2);
printf("\narr2 in main {%d, %d}\n",arr2[0],arr2[1]);
return 0;
}
We all know that passing array as argument is a call by reference. As if I send an array arr={99,99} to a function which makes arr[0]=4 and arr[1]=5, the values get changed to 4 and 5 in the calling function also. The same should be applicable if I send the address of the variable and some manipulation is done in other function.
The following output of the above code confused me. I want to be assured if what I am thinking is correct or not.
arr in fun {5, 4}
arr in main {99, 99}
emptyInMainin fun {5, 4}
--commented the line in the code because emptyInMain[0],emptyInMain[1] will give RUNTIME ERROR--
arr2in fun {5, 4}
arr2 in main {99, 99}
following output shows expected behaviour
arr2in fun {4, 5}
arr2 in main {4, 5}
Only the last output shows the change.
Why I think arr did not get changed in first three cases is we are sending address of arr which is stored in local variable of fun(). This local variable starts pointing to some other address after the statement:
arr=(int *)malloc(2*sizeof(int));
anotherFunction() is the only function that doesn't change the allocation of its own local variable and manipulates the value stored in its (local variable's) address.
Please let me know if following assumptions of mine are wrong. Also please let me know what best change can I make to make values in the array change in all the cases. What could I do to make the variable point to location by means of malloc inside the called function (I guess double pointer but not sure).
To answer the question in your title, C parameters are always passed by value, never by reference. What makes arrays different is that when you pass an array as a parameter, it's automatically converted to a pointer to the first element of the array, and this is the value that's passed. All other types of parameters are passed by making a copy of the value.
In either case, assigning to the parameter variable in the function has no effect on the caller's variable. When the parameter is a pointer, you can indirect through it to access the caller's data. And if it's a pointer to an array element, you can index it to access the caller's array. That's what happens in your anotherfunction() function.
If you want to allocate the array in the function and have this affect the caller, there are two ways to do it.
First is to have the function return the pointer:
int *fun() {
int *localarr = malloc(2 * sizeof(int));
localarr[0] = 4;
localarr[1] = 5;
return localarr;
}
Then the caller would do:
arr = fun();
The second way is to pass a pointer to a pointer.
void fun(int **arrparam) {
int *localarr = malloc(2 * sizeof(int));
localarr[0] = 4;
localarr[1] = 5;
*arrparam = localarr;
}
Then the caller does:
fun(&arr);
What could I do to make the variable point to location by means of malloc inside the called function so that variable in main also starts pointing to the new location (I guess double pointer but not sure).
In order to do that, you have pass a pointer to a pointer (that's your double pointer).
foo(int** ptr)
{
*ptr = malloc(sizeof(int)*2);
(*ptr)[0] = 10;
(*ptr)[1] = 20;
}
int main()
{
int* ptr;
foo(&ptr); // Use the & operator to pass a pointer to the pointer.
// Check to make sure that the values are as expected.
assert(ptr[0] == 10);
assert(ptr[1] == 20);
// deallocate the memory
free(ptr);
}

Double Pointers in C and their scope

I have this code:
void alloc2(int** p) {
*p = (int*)malloc(sizeof(int));
**p = 10;
}
void alloc1(int* p) {
p = (int*)malloc(sizeof(int));
*p = 10;
}
int main(){
int *p;
alloc1(p);
//printf("%d ",*p);//value is undefined
alloc2(&p);
printf("%d ",*p);//will print 10
free(p);
return 0;
}
So, I understand that alloc1 just makes a local copy so it's not effecting outside the function the pointer which is given as a parameter.
But what is happening with alloc2?
tl;dr;
And why this alloc1(&p); won't work?
Update
I think i answered my question. The crucial thing is that & makes you a pointer and then a was built to a double pointer bei dereferencing once. Then the double pointer points to the address given be malloc. Finally the address was filled with 10.
And alloc1(&p); would work, but you couldn't derefence the double pointer since it takes a single pointer.
Thanks to all of you
It didn't become a double pointer, in alloc2() you are passing a pointer containing the address of main()'s p. When you dereference it you are actually modifying the address stored in main()'s p. And that's why it's working.
Since there is no pass by reference in c, the only way you can modify a parameter inside a function is by passing a pointer with it's address, for example if you have to pass an integer to a function and the function needs to modify it then you make a pointer using the address of & operator and pass that pointer to the function, example
void
modify(int *pointer)
{
*pointer += 1;
}
int
main(void)
{
int value;
value = 0;
modify(&value);
printf("%d\n", value);
modify(&value);
printf("%d\n", value);
}
would output
1
2
A double pointer is a pointer to a pointer, so you are making a pointer from p in main() which stores the address of p in main(), the pointer itself is stored somewhere, so you are passing the address where the pointer is stored and hence you can modify it's contents from within alloc2().
Note: It's bad style to cast the return valud of malloc(), read more about it here.
It would be clearer if you gave the variables in different functions different names. Since you have multiple variables and arguments named p, and they are distinct from each other, it is easy to confuse yourself.
void alloc2(int** pa2)
{
*pa2 = (int*)malloc(sizeof(int));
**pa2 = 10;
}
void alloc1(int* pa1)
{
pa1 = (int*)malloc(sizeof(int));
*pa1 = 10;
}
int main()
{
int *p = 0;
alloc1(p);
//printf("%d ",*p);//value is undefined
alloc2(&p);
printf("%d ",*p);//will print 10
free(p);
return 0;
}
Apart from renaming the arguments of functions, I've also initialised p in main() to zero (the NULL pointer). You had it uninitialised, which means that even accessing its value (to pass it to alloc1()) gives undefined behaviour.
With p being NULL, alloc1() also receives the NULL pointer as the value of pa1. This is a local copy of the value of p from main(). The malloc() call then changes the value of pa1 (and has no effect on p in main(), since it is a different variable). The statement *pa1 = 10 sets the malloced int to be 10. Since pa1 is local to alloc1() it ceases to exist when alloc1() returns. The memory returned by malloc() is not free()d though (pa1 ceases to exist, but what it points to doesn't) so the result is a memory leak. When control passes back to main(), the value of p is still zero (NULL).
The call of alloc2() is different, since main() passes the address of p. That is the value of pa2 in alloc2(). The *pa2 = (int *)malloc(sizeof(int)) statement does change the value of p in main() - to be the value returned by malloc(). The statement **pa2 = 10 then changes that dynamically allocated int to be 10.
Note also that the (int *) on the result of malloc() is unnecessary in C. If you need it, it means one of
You have not done #include <stdlib.h>. The type conversion forces the code to compile, but any usage of the int - strictly speaking - gives undefined behaviour. If this is the case, remove the int * and add #include <stdlib.h>.
You are compiling your C code using a C++ compiler.

How does the compiler understand whether the given function does a pass by value or pass by referene?

How does the C compiler understand whether the given function does a pass by value or pass by reference?
what will happen if the pointer of a variable is passed as integer (as pass by value) to a function ? OR is this possible in C ?
ie: the address of a variable is copied to another variable(int) and that variable is passed to a function. here the called function will get an address as normal integer parameter. Is this possible in C? if not why?
In C it is possible only the pass by value (by reference is supported only in C++).
Both a standard variable and a pointer variable are passed by value. So, the compiler must not make any check about reference or value.
standard variables and pointer variables are same, both store values, but a pointer variable can store only an address value and supports the dereferencing operator '*', this operator get the value pointed by the pointer variable.
Thanks to this, when you pass by value (C support only by value) a pointer variable, the value of the pointer variable is copied in a local pointer variable (instanced in the function stack) this variable is the pointer argument of the function. So you can access to address value copied in the local pointer variable using the dereferencing operator.
Added comments 08/22/14
I can better explain with a example:
void FuncSet10(int* PtrArgument)
{
// The PtrArgument is a local pointer variable
// it is allocated in the stack. The compiler
// copies the MyIntVariable address in this variable
// Using dereferencing operator I can access to
// memory location pointed by PtrArgument
*PtrArgument = 10;
}
void FuncSet20(int IntArgument)
{
// The IntArgument is a local variable
// allocated in the stack. The compiler
// copies the MyIntVariable address in this variable
// this code emulates the dereferencing operator
// and so poiter mechanism.
*((int*)IntArgument) = 20;
}
void FuncMovePointer(int* pointer)
{
int a = *pointer++; // now a contains 1
int b = *pointer++; // now b contains 2
int c = *pointer++; // now c contains 3
printf("a contains %d\n", a);
printf("b contains %d\n", b);
printf("c contains %d\n", c);
// The *Ptr now points to fourth (value 4) element of the Array
printf("pointer points to %d\n", *pointer);
}
int _tmain(int argc, _TCHAR* argv[])
{
int Array[] = {1, 2, 3, 4}; // Array definition
int* pointer = Array; // pointer points to the array
int MyIntVariable;
// First example for explanation of
// the pointer mechanism and compiler actions
// After calling this function MyIntVariable contains 10
FuncSet10(&MyIntVariable);
printf("MyIntVariable contains %d\n", MyIntVariable);
// After calling this function MyIntVariable contains 20
// This code emulate pointer mechanism
FuncSet20((int)&MyIntVariable);
printf("MyIntVariable contains %d\n", MyIntVariable);
// Second example to demonstrate that a pointer
// is only a local copy in a called function
// Inside function the pointer is incremented with ++ operator
// so it will point the next element before returning by function
// (it should be 4)
FuncMovePointer(pointer);
// But this is not true, it points always first element! Why?
// Because the FuncMovePointer manages a its local copy!
printf("but externally the FuncMovePointer it still points to first element %d\n", *pointer);
return 0;
}
I hope that above code can help better your understanding.
Angelo
How does the C compiler understand whether the given function does a
pass by value or pass by reference?
For your information C not understand about pass by reference. You can send pointer to variable.
what will happen if the pointer of a variable is passed as integer (as
pass by value) to a function ?
Passing the pointers to a variable and the accessing it using dereferencing within the function.So By passing a pointer to a function you can allow that function to read and write to the data stored in that variable.
For example
void myfunc( int *myval ) // pointer "myval" point address of "locvar"
{
*myval = 77; //place value 77 at address pointed by "myval"
}
int main()
{
int locvar=10; //place value 10 at some address of "locvar"
printf("locvar = %d\n",locvar);
myfunc(&locvar); // Here address of "locvar" passed
printf("locvar = %d\n",locvar);
return 0;
}

Double pointers are also sometimes employed to pass pointers to functions by reference

" Double pointers are also sometimes employed to pass pointers to functions by reference "
can somebody can explain me the above statement, what exactly does point to function by reference means ?
I believe this example makes it clearer :
//Double pointer is taken as argument
void allocate(int** p, int n)
{
//Change the value of *p, this modification is available outside the function
*p = (int*)malloc(sizeof(int) * n);
}
int main()
{
int* p = NULL;
//Pass the address of the pointer
allocate(&p,1);
//The pointer has been modified to point to proper memory location
//Hence this statement will work
*p=10;
//Free the memory allocated
free(p);
return 0;
}
It means that you have a function that takes a pointer pointer (type int ** for example). This allows you to modify the pointer (what data it is pointing to) much in the way passing a pointer by reference would allow.
void change (int *p) {*p = 7;}
void Really_Change (int **pp) {*pp = null;}
int p = 1;
int *pp = &p;
// now, pp is pointing to p. Let's say it has address 0x10;
// this makes a copy of the address of p. The value of &p is still 0x10 (points to p).
// but, it uses that address to change p to 7.
change(&p);
printf("%d\n", p); // prints 7;
// this call gets the address of pp. It can change pp's value
// much like p was changed above.
Really_Change(&pp);
// pp has been set to null, much like p was set to 7.
printf("%d\n", *pp); // error dereference null. Ka-BOOM!!!
So, in the same way that you can pass a pointer to an int and change the value, you can pass a pointer to a pointer and change its value (which changes what it points to.)
I'll try to explain with both code and plain english :). The explanation may get long, but it will be worth the while.
Suppose we have a program, running its main() function, and we make a call to another function that takes an int parameter.
Conceptually, When you pass a variable as a parameter to a function, you can do so in (roughly speaking) two ways: by value, or by reference.
"By value" means giving the function a copy of your variable. The function will receive its "content" (value), but it won't be able to change the actual variable outside its own body of code, because it was only given a copy.
"By reference", on the other hand, means giving the function the actual memory address of our variable. Using that, the function can find out the variable's value, but it can also go to that specified address and modify the variable's content.
In our C program, "by value" means passing a copy of the int (just taking int as argument), and "by reference" means passing a pointer to it.
Let's see a small code example:
void foo(int n) {
n = 10;
printf("%d\n", n);
}
int main() {
int n = 5;
foo(n);
printf("%d\n", n);
return 0;
}
What will the output of this program be? 10 10? Nope. 10 5! Because we passed a copy of the int, by value and not by reference, foo() only modified the number stored in its copy, unable to reach main()'s copy.
Now, if we do it this way:
void foo(int* n) {
*n = 10;
printf("%d\n", *n);
}
int main() {
int n = 5;
foo(&n);
printf("%d\n", n);
return 0;
}
This time we gave foo() our integer by reference: it's actual memory address. foo() has full power to modify it by accessing it's position in memory, foo() and main() are working with the same copy, and so the output will be 10 10.
As you see, a pointer is a referece,... but also a numerical position in memory. It's similar to an int, only the number contained inside is interpreted differently. Think of it this way: when we pass our int by reference, we're passing an int pointer by value!. So the same by value/by reference logic can be applied to pointers, even though they already are references.
If our actual variable was not an int, but an int reference (pointer), and we wanted main() and foo() to share the same copy of that reference so that foo() can modifiy it, what would we do? Why of course, we'd need a reference to our reference! A pointer to a pointer. That is:
int n; /* integer */
int* n; /* integer reference(pointer). Stores an int's position in memory */
int** n; /* reference to integer reference, or double pointer.
Stores int*'s memory address so we can pass int*s by reference. */
I hope this was useful.

Resources