C Pointers
Creating Pointers
You learned from the previous chapter, that we can get the memory address of a variable with the reference operator &
:
Example
int myAge = 43; // an int variable
printf("%d", myAge); // Outputs the value of myAge (43)
printf("%p", &myAge); // Outputs the memory address of myAge (0x7ffe5367e044)
A pointer is a variable that stores the memory address of another variable as its value.
A pointer variable points to a data type (like int
) of the same type, and is created with the *
operator.
The address of the variable you are working with is assigned to the pointer:
Example
int myAge = 43; // An int variable
int* ptr = &myAge; // A pointer variable, with the name ptr, that stores the address of myAge
// Output the value of myAge (43)
printf("%d\n", myAge);
// Output the memory address of myAge (0x7ffe5367e044)
printf("%p\n", &myAge);
// Output the memory address of myAge with the pointer (0x7ffe5367e044)
printf("%p\n", ptr);
Example explained
Create a pointer variable with the name ptr
, that points to an int
variable (myAge
). Note that the type of the pointer has to match the type of the variable you're working with (int
in our example).
Use the &
operator to store the memory address of the myAge
variable, and assign it to the pointer.
Now, ptr
holds the value of myAge
's memory address.
Dereference
In the example above, we used the pointer variable to get the memory address of a variable (used together with the &
reference operator).
You can also get the value of the variable the pointer points to, by using the *
operator (the dereference operator):
Example
int myAge = 43; // Variable declaration
int* ptr = &myAge; // Pointer declaration
// Reference: Output the memory address of myAge with the pointer (0x7ffe5367e044)
printf("%p\n", ptr);
// Dereference: Output the value of myAge with the pointer (43)
printf("%d\n", *ptr);
Note that the *
sign can be confusing here, as it does two different things in our code:
- When used in declaration (
int* ptr
), it creates a pointer variable. - When not used in declaration, it act as a dereference operator.
Good To Know: There are two ways to declare pointer variables in C:
int* myNum;
int *myNum;
Notes on Pointers
Pointers are one of the things that make C stand out from other programming languages, like Python and Java.
They are important in C, because they allow us to manipulate the data in the computer's memory. This can reduce the code and improve the performance. If you are familiar with data structures like lists, trees and graphs, you should know that pointers are especially useful for implementing those. And sometimes you even have to use pointers, for example when working with files and memory management.
But be careful; pointers must be handled with care, since it is possible to damage data stored in other memory addresses.
Pointers & Arrays
You can also use pointers to access arrays.
Consider the following array of integers:
Example
You learned from the arrays chapter that you can loop through the array elements with a for
loop:
Example
int myNumbers[4] = {25, 50, 75, 100};
int i;
for (i = 0; i < 4; i++) {
printf("%d\n", myNumbers[i]);
}
Result:
25
50
75
100
Instead of printing the value of each array element, let's print the memory address of each array element:
Example
int myNumbers[4] = {25, 50, 75, 100};
int i;
for (i = 0; i < 4; i++) {
printf("%p\n", &myNumbers[i]);
}
Result:
0x7ffe70f9d8f0
0x7ffe70f9d8f4
0x7ffe70f9d8f8
0x7ffe70f9d8fc
Note that the last number of each of the elements' memory address is different, with an addition of 4.
It is because the size of an int
type is typically 4 bytes, remember:
Example
// Create an int variable
int myInt;
// Get the memory size of an int
printf("%lu", sizeof(myInt));
Result:
4
So from the "memory address example" above, you can see that the compiler reserves 4 bytes of memory for each array element, which means that the entire array takes up 16 bytes (4 * 4) of memory storage:
Example
int myNumbers[4] = {25, 50, 75, 100};
// Get the size of the myNumbers array
printf("%lu", sizeof(myNumbers));
Result:
16
How Are Pointers Related to Arrays
Ok, so what's the relationship between pointers and arrays? Well, in C, the name of an array, is actually a pointer to the first element of the array.
Confused? Let's try to understand this better, and use our "memory address example" above again.
The memory address of the first element is the same as the name of the array:
Example
int myNumbers[4] = {25, 50, 75, 100};
// Get the memory address of the myNumbers array
printf("%p\n", myNumbers);
// Get the memory address of the first array element
printf("%p\n", &myNumbers[0]);
Result:
0x7ffe70f9d8f0
0x7ffe70f9d8f0
This basically means that we can work with arrays through pointers!
How? Since myNumbers is a pointer to the first element in myNumbers, you can use the *
operator to access it:
Example
int myNumbers[4] = {25, 50, 75, 100};
// Get the value of the first element in myNumbers
printf("%d", *myNumbers);
Result:
25
To access the rest of the elements in myNumbers, you can increment the pointer/array (+1, +2, etc):
Example
int myNumbers[4] = {25, 50, 75, 100};
// Get the value of the second element in myNumbers
printf("%d\n", *(myNumbers + 1));
// Get the value of the third element in myNumbers
printf("%d", *(myNumbers + 2));
// and so on..
Result:
50
75
Or loop through it:
Example
int myNumbers[4] = {25, 50, 75, 100};
int *ptr = myNumbers;
int i;
for (i = 0; i < 4; i++) {
printf("%d\n", *(ptr + i));
}
Result:
25
50
75
100
It is also possible to change the value of array elements with pointers:
Example
int myNumbers[4] = {25, 50, 75, 100};
// Change the value of the first element to 13
*myNumbers = 13;
// Change the value of the second element to 17
*(myNumbers +1) = 17;
// Get the value of the first element
printf("%d\n", *myNumbers);
// Get the value of the second element
printf("%d\n", *(myNumbers + 1));
Result:
13
17
This way of working with arrays might seem a bit excessive. Especially with simple arrays like in the examples above. However, for large arrays, it can be much more efficient to access and manipulate arrays with pointers.
It is also considered faster and easier to access two-dimensional arrays with pointers.
And since strings are actually arrays, you can also use pointers to access strings.
For now, it's great that you know how this works. But like we specified in the previous chapter; pointers must be handled with care, since it is possible to overwrite other data stored in memory.