C Pointers (WIP)

I would make a joke about pointers, but you would not get the reference.

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.

C Pointers

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.

Pointers

Source

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:


Pointers