• C Programming Video Tutorials

Pointers in C



Pointers in C are easy and fun to learn. Some complex C programming tasks can be performed more easily with pointers, while some other tasks such as dynamic memory allocation cannot be performed without using pointers. So it becomes necessary to learn pointers to become a perfect C programmer.

With pointers, you can access and modify the data located in the memory, pass the data efficiently between the functions, and create dynamic data structures like linked lists, trees, and graphs.

Example: Address of the Variables

As you know, every variable is a memory location and every memory location has its address defined which can be accessed using the ampersand (&) operator, which denotes an address in memory.

Consider the following example, which prints the address of the variables defined −

#include <stdio.h>

int main(){

   int  var1;
   char var2[10];

   printf("Address of var1 variable: %x\n", &var1);
   printf("Address of var2 variable: %x\n", &var2);

   return 0;
}

Output

When the above code is compiled and executed, it will print the address of the variables −

Address of var1 variable: 61e11508
Address of var2 variable: 61e1150e

What are Pointers?

A pointer is a variable that stores the reference to another variable, which may be of any type such as int, float or char, an array (one or multidimensional), struct or union, or even a pointer type itself.

A pointer is a variable whose value is the address of another variable, i.e., the direct address of a memory location. Like any variable or constant, you must declare a pointer before using it to store any variable address. The general form of a pointer variable declaration is −

type *var-name;

Here, type is the pointer's base type; it must be a valid C data type and var-name is the name of the pointer variable. The asterisk * used to declare a pointer is the same asterisk used for multiplication. However, in this statement the asterisk is being used to designate a variable as a pointer. Take a look at some of the valid pointer declarations −

int    *ip;    /* pointer to an integer */
double *dp;    /* pointer to a double */
float  *fp;    /* pointer to a float */
char   *ch     /* pointer to a character */

The actual data type of the value of all pointers, whether integer, float, character, or otherwise, is the same, a long hexadecimal number that represents a memory address. The only difference between pointers of different data types is the data type of the variable or constant that the pointer points to.

Referencing and Dereferencing in C

A pointer references a location in memory. Obtaining the value stored at that location is known as dereferencing the pointer.

In C, it is important to understand the purpose of the following two operators in the context of pointer mechanism −

  • The & Operator − It is also known as the "Address-of operator". It is used for Referencing which means taking the address of an existing variable (using &) to set a pointer variable.
  • The * Operator − It is also known as the "dereference operator". Dereferencing a pointer is carried out using the * operator to get the value from the memory address that is pointed by the pointer.

Pointers are used to pass parameters by reference. This is useful if a programmer wants a function's modifications to a parameter to be visible to the function's caller. This is also useful for returning multiple values from a function.

How to Use Pointers?

There are a few important operations, which we will do with the help of pointers very frequently. (a) We define a pointer variable, (b) assign the address of a variable to a pointer and (c) finally access the value at the address available in the pointer variable. This is done by using unary operator * that returns the value of the variable located at the address specified by its operand.

Example 1: Using Pointers in C

The following example shows how you can use the & and * operators to carry out pointer-related opeartions in C −

#include <stdio.h>

int main(){

   int  var = 20;   /* actual variable declaration */
   int  *ip;        /* pointer variable declaration */

   ip = &var;   /* store address of var in pointer variable*/

   printf("Address of var variable: %x\n", &var);

   /* address stored in pointer variable */
   printf("Address stored in ip variable: %x\n", ip);

   /* access the value using the pointer */
   printf("Value of *ip variable: %d\n", *ip );

   return 0;
}

Output

Execute the code and check its output −

Address of var variable: db7d8b8c
Address stored in ip variable: db7d8b8c
Value of *ip variable: 20

To declare a pointer variable, the following syntax is to be used −

type *var;

The name of the variable must be prefixed with an asterisk (*).

The data type indicates the type of variable the address of which it can store. For example, "int *x;". Here, the variable "x" is meant to store the address of another int variable.

Similarly, in "float *y; the variable "y" is a pointer that stores the memory location of a float variable.

The & operator returns the address of an existing variable. We can assign it to the pointer variable. Take a look at the following code snippet −

int a;
int *x = &a;

Assuming that the compiler creates the variable "a" at the address 1000 and "x" at the address 2000, then the address of "a" is stored in "x".

variable at the address

The deference operator returns the value at the address stored in the pointer variable. Here "*x" will return the value of "a", i.e., the value stored in the memory address 1000, which in fact is the value of "x". Let us understand this with the help of the following example.

Example 2

We will declare an int variable and display its value and address −

#include <stdio.h>

int main(){

   int var = 100;
   
   printf("Variable: %d \t Address: %d", var, &var);
}

Output

Run the code and check its output −

Variable: 100   Address: 6422044

Example 3

We can also use %p format specifier to obtain the hexadecimal number of the memory address.

#include <stdio.h>

int main(){
   
   int var = 100;
   
   printf("Variable: %d \nAddress: %p", var, &var);
}

Output

Run the code and check its output −

Variable: 100  
Address: 000000000061FE1C

Example 4

In this example, the address of var is stored in the intptr variable with & operator

#include <stdio.h>

int main(){

   int var = 100;
   int *intptr = &var;
   
   printf("Variable: %d \nAddress of Variable: %d \n\n", var, &var);
   printf("intptr: %ld \nAddress of intptr: %d \n\n", intptr, &intptr);
}

Output

Run the code and check its output −

Variable: 100 
Address of Variable: 2043225868 

intptr: 140722351712012 
Address of intptr: 2043225872

Example 5

Now let's take an example of a float variable and find its address −

#include <stdio.h>

int main(){

   float var1 = 10.55;
   
   printf("var1: %f \n", var1);
   printf("Address of var1: %d", &var1);
}

Output

Run the code and check its output −

var1: 10.550000 
Address of var1: 1512452612

We can see that the address of this variable (any type of variable for that matter) is an integer. So, if we try to store it in a pointer variable of "float" type, see what happens −

float var1 = 10.55;
int *intptr = &var1;

The compiler doesn’t accept this, and reports the following error

initialization of 'int *' from incompatible pointer type 
'float *' [-Wincompatible-pointer-types]

Note: The type of a variable and the type of its pointer must be same.

In C, variables have specific data types that define their size and how they store values. Declaring a pointer with a matching type (e.g., float *) enforces "type compatibility" between the pointer and the data it points to.

Different data types occupy different amounts of memory space in C. For example, an "int" typically takes 4 bytes, while a "float" might take 4 or 8 bytes depending on the system. Adding or subtracting integers from pointers moves them in memory based on the size of the data they point to.

Example 6

In this example, we declare a variable "floatptr" of "float *" type.

#include <stdio.h>

int main(){

   float var1 = 10.55;
   float *floatptr = &var1;
   
   printf("var1: %f \nAddress of var1: %d \n\n", var1, &var1);
   printf("floatptr: %d \nAddress of floatptr: %d", floatptr, &floatptr);
}

Output

var1: 10.550000 
Address of var1: 443414940 

floatptr: 443414940 
Address of floatptr: 443414944

The * operator is called the dereference operator. It returns the value of the variable that the pointer is pointing to.

Example 7

Take a look at the following example −

#include <stdio.h>

int main(){

   float var1 = 10.55;
   float *floatptr = &var1;
   
   printf("var1: %f \nAddress of var1: %d \n\n",var1, &var1);
   printf("floatptr: %d \nAddress of floatptr: %d \n\n", floatptr, &floatptr);
   printf("var1: %f \nValue at floatptr: %f", var1, *floatptr);
}

Output

Run the code and check its output −

var1: 10.550000 
Address of var1: 451729484 

floatptr: 451729484 
Address of floatptr: 451729488 

var1: 10.550000 
Value at floatptr: 10.550000

We may have a pointer variable that stores the address of another pointer itself.

Pointer Variable

In the above figure, "a" is a normal "int" variable, whose pointer is "x". In turn, the variable stores the address of "x".

Note that "y" is declared as "int **" to indicate that it is a pointer to another pointer variable. Obviously, "y" will return the address of "x" and "*y" is the value in "x" (which is the address of "a").

To obtain the value of "a" from "y", we need to use the expression "**y". Usually, "y" will be called as the pointer to a pointer.

Example 8

Take a look at the following example −

#include <stdio.h>

int main(){

   int var = 10;
   int *intptr = &var;
   int **ptrptr = &intptr;
   
   printf("var: %d \nAddress of var: %d \n\n",var, &var);
   printf("inttptr: %d \nAddress of inttptr: %d \n\n", intptr, &intptr);
   printf("var: %d \nValue at intptr: %d \n\n", var, *intptr);
   printf("ptrptr: %d \nAddress of ptrtptr: %d \n\n", ptrptr, &ptrptr);
   printf("intptr: %d \nValue at ptrptr: %d \n\n", intptr, *ptrptr);
   printf("var: %d \n*intptr: %d \n**ptrptr: %d", var, *intptr, **ptrptr);
   
   return 0;
}

Output

Run the code and check its output −

var: 10 
Address of var: 951734452 

inttptr: 951734452 
Address of inttptr: 951734456 

var: 10 
Value at intptr: 10 

ptrptr: 951734456 
Address of ptrtptr: 951734464 
intptr: 951734452 
Value at ptrptr: 951734452 

var: 10 
*intptr: 10 
**ptrptr: 10

You can have a pointer to an array as well as a derived type defined with struct. Pointers have important applications. They are used while calling a function by passing the reference. Pointers also help in overcoming the limitation of a function’s ability to return only a single value. With pointers, you can get the effect of returning multiple values or arrays.

NULL Pointers

It is always a good practice to assign a NULL value to a pointer variable in case you do not have an exact address to be assigned. This is done at the time of variable declaration. A pointer that is assigned NULL is called a null pointer.

The NULL pointer is a constant with a value of "0" defined in several standard libraries.

Example

Consider the following program −

#include <stdio.h>

int main(){

   int *ptr = NULL;

   printf("The value of ptr is : %x\n", ptr);
 
   return 0;
}

Output

When the above code is compiled and executed, it produces the following result −

The value of ptr is 0

In most operating systems, programs are not permitted to access memory at address "0" because that memory is reserved by the operating system.

The memory address "0" has a special significance; it signals that the pointer is not intended to point to an accessible memory location. But by convention, if a pointer contains the null (zero) value, it is assumed to point to nothing.

To check for a null pointer, you can use an if statement as follows −

if(ptr)     /* succeeds if p is not null */
if(!ptr)    /* succeeds if p is null */

Pointers in Detail

Pointers have many but easy concepts and they are very important to C programming. The following important pointer concepts should be clear to any C programmer −

Sr.No Concept & Description
1 Pointer arithmetic

There are four arithmetic operators that can be used in pointers: ++, --, +, -

2 Array of pointers

You can define arrays to hold a number of pointers.

3 Pointer to pointer

C allows you to have pointer on a pointer and so on.

4 Passing pointers to functions in C

Passing an argument by reference or by address enable the passed argument to be changed in the calling function by the called function.

5 Return pointer from functions in C

C allows a function to return a pointer to the local variable, static variable, and dynamically allocated memory as well.

Advertisements