Mastering Pointers in C: Tips and Tricks

Pointers are the variables which are used to store/hold address of another variables. In one sense, any variable in C is just a convenient label for a chunk of the computer’s memory that contains the variable’s data. A pointer, then, is a special kind of variable that contains the location or address of that chunk of memory. (Pointers are so called because they point to a chunk of memory.) The address contained by a pointer is a lengthy number that enables you to pinpoint exactly where in the computer’s memory the variable resides.

Pointers are one of the more versatile features of C. There are many good reasons to use them. Knowing a variable’s address in memory enables you to pass the variable to a function by reference. Also, since functions are just chunks of code in the computer’s memory, and each of them has its own address, you can create pointers to functions too, and knowing a function’s address in memory enables you to pass functions as parameters too, giving your functions the ability to switch among calling numerous functions.

Pointer Declaration: For the declaration of pointer at first we write date type followed by asterisk ( * ) then we write pointer name.: Data Type * Pointer_Name;

For example, suppose we have to declare a pointer to hold the address of integer variable we will declare it as following:

int *p;

Above instruction will declare a pointer P that can hold an address of integral variable.

Accessing memory of variable using Pointer: For accessing memory using pointer at first we need to assign memory address to pointer, then we can access, update or insert contents to  that memory area. To do this at first we reference it then dereference it.

Referencing Operation: Providing reference we write pointer name followed by assignment operator then we write or provide an address.

Pointer_Name = Address of memory(or location).

For example we have an integer i and its value is 10, an we have to access it using pointer

For that  we need to declare a pointer and assign the address of i to it. We do it using following:

int *p;
p = &i;     // This is called referencing.

Now to access the contents of memory we need to dereference it.

Dereferencing a Pointer: Pointer is dereferenced using asterisk or dereference operator (i.e. * ) followed by pointer name.

*p      // this is called dereferencing.

To create a pointer to a variable, we use the * and & operators.

For example, the following code declares a variable called total_cost and a pointer to it called total_cost_ptr.

float total_cost;
float *total_cost_ptr;
total_cost_ptr = &total_cost;

The `*’ symbol in the declaration of total_cost_ptr is the way to declare that variable to be a pointer in C. you can pronounce the above statement float *total_cost_ptr as Declare a float pointer called total_cost_ptr, and you can pronounce the statement total_cost_ptr = &total_cost;  as  total_cost_ptr take as its value the address of the variable total_cost.

Pointer Notation

Consider the declaration,

int i = 3 ; 

This declaration tells the C compiler to:

(a) Reserve space in memory to hold the integer value.

(b) Associate the name i with this memory location.

(c) Store the value 3 at this location.

We may represent i’s location in memory by the following memory map.

We see that the computer has selected memory location 65524 as the place to store the value 3. The location number 65524 is not a number to be relied upon, because some other time the computer may choose a different location for storing the value 3. The important point is, i’s address in memory is a number.

We can print this address number through the following program:

main( ) 
{ 
int i = 3 ; 
printf ( "\nAddress of i = %u", &i ) ; 
printf ( "\nValue of i = %d", i ) ; 
} 

The output of the above program would be:

Address of i = 65524 
Value of i = 3 

Look at the first printf( ) statement carefully. ‘&’ used in this statement is C’s ‘address of’ operator. The expression &i returns the address of the variable i, which in this case happens to be 65524. Since 65524 represents an address, there is no question of a sign being associated with it. Hence it is printed out using %u, which is a format specifier for printing an unsigned integer. We have been using the ‘&’ operator all the time in the scanf( ) statement.

The other pointer operator available in C is ‘*’, called the ‘value at address’ operator. It gives the value stored at a particular address. The ‘value at address’ operator is also called the ‘indirection’ operator.

Consider the following memory map. As you can see, i’s value is 3, and j’s value is i’s address.

j is a variable that contains the address of i, it is declared as,

int *j ; 

This declaration tells the compiler that j will be used to store the address of an integer value. In other words j points to an integer. How do we justify the usage of * in the declaration,

int *j ; 

Let us go by the meaning of *. It stands for ‘value at address’. Thus, int *j would mean, the value at the address contained in j is an int.

Here is a program that demonstrates the relationships we have been discussing.

main( ) 
{ 
int i = 3 ; 
int *j ; 
j = &i ; 
printf ( "\nAddress of i = %u", &i ) ; 
printf ( "\nAddress of i = %u", j ) ; 
printf ( "\nAddress of j = %u", &j ) ; 
printf ( "\nValue of j = %u", j ) ; 
printf ( "\nValue of i = %d", i ) ; 
printf ( "\nValue of i = %d", *( &i ) ) ; 
printf ( "\nValue of i = %d", *j ) ; 
} 

The output of the above program would be:

Address of i = 65524 
Address of i = 65524 
Address of j = 65522 
Value of j = 65524 
Value of i = 3 
Value of i = 3 
Value of i = 3

Significance or importance or advantages of Pointers:

Pointer is used in memory management, optimization, function parameters, etc.

  • Memory management: Allocating and deallocating memory as needed during run time allows you to create large objects, quickly and immediately free the memory when it is no longer required.
  • Optimization: Pointers provide a performance advantage by allowing you to access computer memory directly. In a computer program, the fastest way to access and modify an object is to directly access the physical memory where that object is stored.
  • Function Parameters: Functions can return only one value, but they can take multiple parameters. By passing in pointers to variables as parameters, a function can be used to set the values of those variables, and the new values will persist after the function returns. Being able to set the value of several variables at once with a single function call is clean and efficient.

Other uses of pointers are following:

  • Pointers allow you to implement sharing without copying i.e. pass by reference v/s pass by copying. This allows a tremendous advantage when you are passing around big arrays as arguments to functions. Here you will not have to call function again and again.
  • Pointers allow us to use dynamic memory allocation.
  • Pointers obviously give us the ability to implement complex data structures like linked lists, trees, etc
  • Pointers allow us to resize the data structure whenever needed. For example, if you have an array of size 10, it cannot be resized. But, an array created out of malloc and assigned to a pointer can be resized easily by creating a new memory area through malloc and copying the old contents over.