The top-level answer to this is that pointers often lead to smaller and faster code. As answers go, that’s not very enlightening though so here are a few concrete examples.

  • To allow functions to change data owned by their caller. This allows you to avoid using global variables for changing data within functions. It also allows you to avoid passing large chunks of data as parameters and as return values.
  • To use memory efficiently both in terms of execution speed and memory usage. For example, nodes in a linked list point to each other. Deleting an element in an array means moving all the ‘higher up’ elements down by one to fill the gap. Deleting an element from a linked list simply involves changing one pointer.
  • Dynamic memory allocation. If you don’t know how much you’ll need at compile time or if the stack isn’t big enough you can grab chunks from the heap at run time. You can’t do this using arrays because they have to have their size defined at compile time.
  • Untyped things. e.g. malloc, free, memset, memcpy etc just deal with memory rather than typed objects.
  • Pointers can hide data and implementation in structs by passing pointers to opaque struct tags. e.g. FILE *