Understand pointers in C programming language
Introduction
If you’re a programmer and are familiar with initializing variables with data, placing reusable code in functions, run different code based on conditions, and done some repetitive tasks in loops— but has now entered the C programming world and wonder what those pointers are?
In C and other programming languages, if you create a variable, you allocate space for it in memory. The variable gets stored in memory under program execution:
Think of the memory as a tape with cells as drawn here, where every cell stores 1 byte. Here it is allocated space for the variable age (with the value 25) in memory, and the location in memory is called an address (here 1000). The address is usually hexadecimal, like 0xb73eb000 or similar, but for simplicity, I’ll just use simpler address numbers.
NOTE: Everything is stored as 0’s and 1’s in memory, and not like 25 in the age-variable illustrated above. And different data types take up a different number of cells (number of bytes) in memory. For simplicity I’ll keep it simple like in the drawing above.
With pointers in C, you can create a pointer variable that points to another address in memory. This means that if you make a pointer variable that points to the variable age, it points to the same address in memory as the age variable has:
Here you see a new variable with the name pointer that is marked as a pointer variable with *. To point to the address in memory where the variable age is stored, you use & before the variable name, this gets the address of age in memory.
Creating and accessing pointers in C
Now that you have seen how to point to other addresses in memory with a pointer variable here's an example in code:
int age = 25;
int *pointer; pointer = &age;
The above code is creating a regular variable age, and a pointer variable pointer then it assigns the address of the age variable to the pointer variable. You can also create pointers with the following formats:
int * pointer;
int* pointer;
Now you can access both value and address of age variable through the pointer:
1 printf("%d", age); // prints: 25
2 printf("%d", *pointer); // prints: 25
3 printf("%p", &age); // prints: 0x7ffddb313f3c
4 printf("%p", pointer); // prints: 0x7ffddb313f3c
5 printf("%p", &pointer); // prints: 0x7fff6433e680
In the code above in line 2, you can see that the pointer can get the value stored in age with *pointer. This is like saying “go to the address of age and get the value stored in that address”.
Next at line 3, we print out the address where age is stored in memory (%p is used to print out addresses), since the pointer points to that address the output is the same at line 4. Another thing to notice is that the pointer itself has its own address as we saw in the second illustration.
Changing values with pointers
If you want to change the value in the address that the pointer variable points to with the pointer itself, you have to use * so that it's getting the value stored in that address and not the address itself — this is called dereferencing.
To change the value of the age variable with the pointer:
*pointer = 26;printf("%d", age); // prints: 26
printf("%d", *pointer); // prints: 26
As you can see changing value with pointer changes the value of age also.
Arrays
Till now I only showed pointer variables to single elements, you can also create a pointer to arrays. An important thing to remember about pointers to arrays is that a pointer variable points to the first element in the array:
After watching this illustration let's create it with code:
char name[] = {'J','o','h','n'};char *pointer = name;
In the above code, you can see an array of character and a pointer variable that point to the character array. Noticed that this time that no & symbol is needed before the name-array before assigning it to the pointer variable? This is because on every array when you access it with just the name (without []), you get back the address of the first element in the array.
With that in mind let's see different ways to access addresses and values of array-pointers:
char name[] = {'J','o','h','n'};char *pointer = name;printf("%p\n", name); // prints: 0x7ffee8098dec
printf("%c\n", name[0]); // prints: J
printf("%c\n", *name); // prints: Jprintf("%p\n", pointer); // prints: 0x7ffee8098decprintf("%c\n", *pointer); // prints: J
printf("%c\n", *(pointer+1)); // prints: o
printf("%c\n", *(pointer+2)); // prints: h
printf("%c\n", *(pointer+3)); // prints: n
Using the pointer address and adding integers like the three last lines above, you jump x places next from a memory location, you can therefore access the next elements in arrays.
Double and triple pointers
As you can point directly to an address for a regular variable, you can also point to other pointers that, in the end, points to an address of a regular variable. To better understand this, here's an example:
int num1= 10;
int *num2 = &num1;
int **num3 = &num2;
int ***num4 = &num3;
To visualize:
Finally, some common use cases of pointers in C
Pointers as functions parameters
In C, you can pass addresses as arguments into functions. To do this you declare the function with pointer parameter(s).
This can be used to change the values of the input variables so that values will also change outside the function scope. Here’s an example:
#include <stdio.h>void increment(int *n);
int main() {
int num = 5;
increment(&num); // address of num is passed
printf("num = %d", num); // prints: 6
return 0;
}
void increment(int *n) {
*n += 1;
}
The code example above shows how pointers are used as function parameters, changing parameter value inside function also changes value outside the scope of the function.
Dynamic memory allocation
C has dynamic memory allocation functions from its standard library:
- malloc() — memory allocation
- calloc() — contiguous allocation
- realloc() — reallocate
- free() — release allocated space
Let’s see an example of using malloc() and free() to dynamically allocate space.
#include <stdio.h>
#include <stdlib.h>
int main() {
int n, *ptr, sum = 0;
printf("Enter number of int elements to allocate memory for: ");
scanf("%d", &n);
ptr = (int*) malloc(n * sizeof(int));
// if memory cannot be allocated
if(ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
free(ptr); // release allocated space
return 0;
}
This program allocates space in memory for type int (4 bytes), so if the user inputs 3, malloc() allocated 3 * 4 bytes = 12 bytes in memory.
File reading
Pointers are also used to read/write files. Here’s an example that writes text to a file:
#include <stdio.h>
#include <stdlib.h>
int main() {
char sentence[400];
FILE *fptr;
fptr = fopen("C:\\input.txt","w");
if(fptr == NULL) {
printf("Error!");
exit(1);
} printf("Enter a sentence:\n");
fgets(sentence, sizeof(sentence), stdin);
fprintf(fptr, "%s", sentence);
fclose(fptr); return 0;
}
The above example uses a pointer to a FILE, which opens a file and points to it in memory.
Summary
A pointer is just a memory location where data is stored, the pointer is used to access data in that memory location. The pointer can be used to change values stored in the address it points to. In C, pointers are used in dynamic memory allocation, arrays, function parameters, and more.