In my last post, I've written about lots of things but not about C pointers. I tought the topic deserves a post in itself because it's one of the most important feature of the C language.
Let's start with some music please.

ToC
Introduction:
A pointer is a variable that contains the memory address of another variable. A pointer allows us to indirectly access and manipulate the value of the variable that is pointed to. Like other variables, C pointers have a type.

Declaration and initialization:
#include <stdio.h>
#include <stdlib.h>
int main () {
int foo = 42;
int bar = 83;
int *ptr = &foo; // Pointer variable of type int*
int **ptrptr = &ptr; // pointer to a pointer
printf("Value of foo: %d\n", foo);
printf("Value of ptr is: %p, and ptr is pointing to: %d\n", (void *)ptr, *ptr);
printf("Value of ptrptr is: %p & ptrptr is pointing to: %p\n", (void *)ptrptr, (void *)ptr);
printf("\n");
*ptr = 12;
printf("Value of foo after modification via ptr: %d\n", foo);
**ptrptr = 13;
printf("Value of foo after modification via ptr to ptr: %d\n", foo);
printf("\n");
ptr = &bar;
printf("Value of ptr is now: %p, and ptr is now pointing to: %d\n", (void *)ptr, *ptr);
printf("Value of ptrptr, still: %p & ptrptr is now pointing to: %p\n", (void *)ptrptr, (void *)ptr);
exit(EXIT_SUCCESS);
}
And the output of the previous program is:
Value of foo: 42
Value of ptr is: 0x7ffc6155fd60, and ptr is pointing to: 42
Value of ptrptr is: 0x7ffc6155fd68 & ptrptr is pointing to: 0x7ffc6155fd60
Value of foo after modification via ptr: 12
Value of foo after modification via ptr to ptr: 13
Value of ptr is now: 0x7ffc6155fd64, and ptr is now pointing to: 83
Value of ptrptr, still: 0x7ffc6155fd68 & ptrptr is now pointing to: 0x7ffc6155fd64
C pointer operators:
C offers operators for pointer manipulation:
- Address-of operator (&): to return the memory address of a variable
- Dereference operator (*): to access the value stored at the memory address pointed to
- Arithmetic operators: to perform arithmetic operations on C pointers, addition (+), subtraction (-), increment (++), and decrement (--)
Use cases for C pointers:
All modern programming languages have pointers in some form or other. Pointers are used everywhere there is a program, even when we don't see them. Let's explore some of those use cases.
Manipulating array and string elements:
C Pointers can be used to access and manipulate elements in arrays and strings. C Pointers provide a way to efficiently iterate over arrays and perform operations on each item of the sequence.
int arr[5] = {1, 2, 3, 4, 5};
int *aptr = arr;
// print items of the sequence using array indices
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// print elements of the array using pointer
for (int i = 0; i < 5; i++) {
printf("%d ", *aptr);
aptr++;
}
// print items of the sequence using pointer arithmetic
// and the fact that arr is actually a pointer to the first item of the arr
for (int i = 0; i < 5; i++) {
printf("%d ", *arr+i);
}
// an array of characters
char str[] = "Hello world from West Africa";
char *sptr = str; // a pointer to the first element of the array
int i = 0;
while(i < 28){
// while i is less than 28, print the character at i-th index
printf("%c ", str[i]);
// increment i to go to the next index
i++;
}
printf("\n");
// while the value that is pointed to is different from the "\0" character
while (*sptr != '\0') {
// print the char
printf("%c ", *sptr);
// increment pointer (to go to the next character)
sptr = sptr + 1;
}
printf("\n");
int m = 0;
while(m < 28){
// str is actually a pointer to the first item of the object
// so str+m is the address of the m-ieth item of the object
printf("%c ", *(str+m));
m++;
}
// array of pointers to characters
char *names[] = {"Alice", "Bob", "Charlie", "David", "Emma"};
// Pointer to the first element of the first element of the array of strings
char **ptr_names = names;
for (int j = 0; j < 5; j++) {
// Print elements of the array of strings using indices
printf("%s\n", names[j]);
}
for (int x = 0; x < 5; x++) {
// Print the element currently pointed to
printf("%s\n", *ptr_names);
ptr_names = ptr_names + 1;
}
Passing arguments by reference:
C Pointers can be used to pass arguments by reference to functions, allowing the function to modify the value of the original variable. This is particularly useful in the following situations:
- working with large data structures
- you need to modify the value of a variable in a function
- you need to optimize code by reducing the number of copies of data that need to be made
- you need to return more than one value
Examples:
Allocating memory:
C Pointers are also used to allocate memory dynamically at run-time using functions like malloc(), calloc(), and realloc(). Examples:
Implementing data structures:
Linked lists, Stacks, Queues, Trees, Graphs and many other data structures are implemented using C Pointers. Examples:
Calling functions:
A function pointer, is a pointer which point to the memory address of a function instead of pointing to the address of a data object. They are used to:
- store functions in data structures
- pass functions as arguments to other functions
- call functions dynamically at runtime
Here are three examples of using function pointers in C:
Interfacing with hardware:
C Pointers are often used in low-level programming to interact with hardware devices and memory-mapped registers. They provide a way to access specific memory addresses and manipulate hardware directly.
Going further:
To learn more about C pointers, we recommend the following pointers:
