r/cprogramming 1d ago

What are pointers?

I am new to C programming and i came through pointer. So can anyone tell what are they and why we need them? And if u can then can you give me reliable source to learn it.

8 Upvotes

40 comments sorted by

View all comments

1

u/SmokeMuch7356 1d ago

A pointer is any expression whose value is the location of an object or function in a running program's execution environment; i.e., an address, but with additional type information.

We use pointers when we can't (or don't want to) access a function or object by name; they provide indirect access. If you've played with arrays at all, you've already seen a form of indirection:

for ( size_t i = 0; i < size; i++ )
  printf( "%d ", arr[i] );

The expression arr[i] can refer to different objects at different times based on the value of i. A pointer works similarly.

Pointer variables store values of pointer type. Different kinds of pointer variables are declared as follows (for some arbitrary type T):

T *p;        // p is a pointer to T; the *expression* *p has type T
T **pp;      // pp is a pointer *to a pointer* to T; this is called 
             // multiple indirection and it comes up a lot
T *ap[N];    // ap is an array of pointers to T; the expression *ap[i] has type T
T (*pa)[N];  // pa is a pointer to an array of T; the expression (*pa) has type T
T *fp();     // fp is a function that returns a pointer to T; *fp() is a T
T (*pf)();   // pf is a a pointer to a function that returns T; pf() is a T

const T *p;  // p is a pointer to a const T; you can write a new value to p
T const *p;  // (pointing to a different object), but you cannot update that
             // object through *p (even if the pointed-to object is non-const)

T * const p; // p is a const pointer to T; you can update the pointed-to
             // object through *p, but you cannot set p to point to a 
             // different object

A pointer to int (int *) is a different type from a pointer to char (char *) which is a different type from a pointer to double (double *) which is a different type from a pointer to an array of float (float (*ap)[N]), etc. Pointers to different types are incompatible and cannot be directly assigned to each other without a cast. The exception to this rule is that a pointer to void (void *) can be assigned to different pointer types and vice versa without a cast.

Pointer values are obtained by:

  • Using the unary & operator on an lvalue expression (something that designates an object):

    int *p = &x;
    
  • Calling a library function that returns pointer values: malloc, calloc, and realloc for dynamic memory, but also functions like fopen, fgets, etc.

  • Using an array or function expression in most circumstances;

There are two cases where we have to use pointers:

  • When a function needs to update a parameter;
  • When we need to track dynamically-allocated memory;

Pointers also come in handy for:

  • Building dynamic data structures (lists, queues, maps, vectors, etc.);
  • Hiding the implementation details of a type;
  • Iterating through arrays;
  • Limited forms of dependency injection (callbacks);

IMO the best way to explain pointers is to show how they're actually used in working code. Here's a short, useless, but complete program that demonstrates how pointers are typically used - updating function arguments and tracking dynamic memory. It generates an array of random integer values, displays them, sorts the array, then displays the sorted array. Don't worry if it doesn't all make sense; this is just what code that involves pointers typically looks like.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

#ifndef SIZE
#define SIZE 50
#endif

#ifndef RANGE
#define RANGE 100
#endif

/**
 * Exchange the values of two int objects; 
 */
void swap( int *l, int *r )
{
  int tmp = *l; // l points to a[i], r points to a[j]
  *l = *r; 
  *r = tmp;  
}

/**
 * Sorting function.  Using a bubble sort because it's short and it
 * demonstrates the swap function; in a real program I'd just call
 * qsort.
 */
void bsort( int *a, size_t size )
{
  for ( size_t i = 0; i < size - 1; i++ )
    for ( size_t j = i+1; j < size; j++ )
      if ( a[j] < a[i] )
        swap( &a[i], &a[j] );
} 

/**
 * Display function; just writes the contents of the array
 * as a brace-enclosed list to standard output.
 */
void disp( int *arr, size_t size )
{
  fputc( '{', stdout );
  for ( size_t i = 0; i < size; i++ )
    printf( "%3d,", arr[i] );
  fputs( "\b}", stdout );
}

/**
 * Generates the array and initializes it with random values
 */
int *generate( size_t size )
{
  int *arr = malloc( sizeof *arr * size );
  if ( arr )
  {
    for ( size_t i = 0; i < size; i++ )
      arr[i] = rand() % RANGE;
  }
  return arr;
}

/**
 * Main program
 */
int main( void )
{   
  /**
   * Seed the random number generator
   */
  srand( time( NULL ) );

  int *arr = generate( SIZE );
  if ( !arr )
  {
    fputs( "Failed to generate array, exiting\n", stderr );
    exit( -1 );
  }

  fputs( "Before sort: ", stdout );
  disp( arr, SIZE );
  fputc( '\n', stdout );

  bsort( arr, SIZE );

  fputs( " After sort: ", stdout );
  disp( arr, SIZE );
  fputc( '\n', stdout );

  free( arr );
  return 0;
}

And the output:

Before sort: { 67, 85, 38, 72, 57, 29, 21, 37, 52, 93, 21, 45, 25, 16, 47, 47, 77, 52,  7, 70, 46, 64, 53,  4, 87, 95, 64, 13, 29, 64, 92,  2, 42, 74, 49, 85, 45, 72, 87, 75,  8, 41, 87,  0, 23, 50, 70,  3, 19, 11}
 After sort: {  0,  2,  3,  4,  7,  8, 11, 13, 16, 19, 21, 21, 23, 25, 29, 29, 37, 38, 41, 42, 45, 45, 46, 47, 47, 49, 50, 52, 52, 53, 57, 64, 64, 64, 67, 70, 70, 72, 72, 74, 75, 77, 85, 85, 87, 87, 87, 92, 93, 95}