Pointers in C (and C++) are not really that difficult if you think about them the right way.
Let me demonstrate with the following code:
void foo(int i) {
i = i + 5;
}
int main()
{
int i = 5;
foo(i);
printf("i is %d\n", i);
return 0;
}
Q. What will be the value of i
in main()
after foo()
is called?
A. i
is passed to foo()
by value, so the i
in main()
is not modified by foo()
. i
is still 5.
Now, let's change the code a bit:
void foo(int* i) {
i = malloc(sizeof(int));
}
int main()
{
int *i = 0;
foo(i);
printf("i is %p\n", i); /* printf a pointer with %p */
return 0;
}
Q. What will be the value of i
in main()
after foo()
is called?
A. i
is passed to foo()
by value, so the i
in main()
is not modified by foo()
. i
is still 0.
In other words, nothing has changed! The fact that i
is now a pointer does not change that it is being passed by value.
Actually, in C, all function parameters are by value. So, how do we get a function to modify a variable?
If you want to pass a variable to a function for that function to modify it, you must pass the address of that variable to the function. (This is true for C. In C++ you can also use references, but I'm speaking only about pointers here.)
When you pass the address of a variable, you are doing two things:
The memory address can be used to modify the memory to which the memory address points. Since the memory address inside the function is the same as the one outside the function call (because it's passed by value), the variable they point to is the same one!
This is really the trickiest concept, so let's draw some ascii.
| |
+------------+ <- 0x04762198
| |
| i |
| |
| |
+------------+ <- 0x0476219C
| |
Let me introduce you to int i
. i
is 4 bytes (on this system) starting at memory address 0x04762198
. All variables are stored somewhere in memory and will be at memory addresses such as this.
If we assign a value to i
, the value will be stored in the above block of memory.
If we pass i
to a function, the value of i
will be copied to somewhere else in memory for use by the function. The value of that memory will be the same as our original i
, but the memory address of that variable will be somewhere else.
Here's the ingenious bit. If we instead pass 0x04762198
to a function, that function now has access to the memory location of the original i
! This is a pointer, so called because it points to an address in memory. If we want to modify the original i
inside the function using the pointer, we dereference it (eg. *ptr = 5;
). What we are actually doing is saying "please store this value (5) in the memory pointed to by ptr
").
Let's change the code again to implement this:
/*
* The address of an int* is int**
*/
void foo(int** i) {
/* dereference to access and modify the original `i` */
*i = malloc(sizeof(int));
}
int main()
{
int *i = 0;
/*
* Pass the address of i, so foo() can modify i
*/
foo(&i);
printf("i is %p\n", i); /* printf a pointer with %p */
return 0;
}
See the difference?
Now, can you see what you are doing wrong in your own program?
NOTE: I have left out the usual error checking (eg. checking that malloc() does not return NULL) for brevity.