How To Use Pointers In C Language

Example

Data_type *pointer_name;

Points to understand:

  • * -> Indirection Operator -> denotes "value at".
  • & -> Address Operator -> denotes "the address of"
  • "*" gives the value stored in the variable, whose address the pointer is pointing at. Using "&" gives the address of the variable or pointer.
  • The address of a variable or an entity is dependent on the OS or the machine. We can't predict the address of an entity unless it's in an array and the base address and the data type are known.

Example:

Example

int *p;

Here, p is an integer data type pointer.

A pointer of a particular data type is capable of holding only the memory address of an entity of that specific data type. Attempting to store the address of a variable with a different data type will result in a warning.

Example:

Example

#include<stdio.h>
int main()
{
	int *ptr;
	float a=9;
	ptr = &a;
	printf("%d",a);
}

Warning:

Example

warning: assignment to 'int *' from incompatible pointer type 'float *

ImportanLogic Practices:

  • A pointer always has whole numbers stored in it because it stores the address, and the address can't be negative or a fraction.
  • A pointer is always initialized to null, and the value of a null pointer is 0. int *p = null; Then, we give it the address we want for no confusion as always a declared variable needs to be initialized to 0 and so pointer to null.
  • Here, if a pointer is initialized to NULL, it is noLogic Practiceing to any entity.
  • Simple example program:

    Example
    
    #include <stdio.h>
    int main()		
    {
       int *ptr;
       int b = 50; 				
       ptr = &b;            
       printf("Value of  b =%d", b);
       printf("\nAddress of  b =%u", &b);
       printf("\nAddress of  ptr =%u", &ptr);     
       printf("\nValue of  ptr =%d", *ptr); 
       printf("\nThe pointer stores =%d", ptr); 
       return 0;
    }
    

Output:

Output

Value of  b =50
Address of  b =6487572
Address of  ptr =6487576
Value of  ptr =50
The pointer stores =6487572

The values of b and *ptr are identical since ptr holds the value of b. The memory address of variable b matches the value stored in the pointer. The memory address of the pointer is separate and distinct.

Referencing and Dereferencing operators:

Referencing: It involves obtaining the memory address of a variable by using the "&" operator.

Dereferencing involves using the "*" operator to retrieve the value stored at a pointer.

Therefore, the reference and dereference operators are also known as "&" and "*".

Arithmetic on Pointers

Imagine a scenario where an integer pointer is referencing a variable located at memory address 500:

Expression Evaluation
ptr = ptr + 1 ptr = 500 + 1*4 = 504
ptr++ or ++ptr 504 + 1*4 = 508
ptr = ptr + 4 508 + 4*4 = 524
ptr = ptr - 2 524 - 2*4 = 516
ptr -- or --ptr 516 - 1*4 = 512

Remember that 4 is the size of the integer data type.

Another example:

Code:

Example

#include <stdio.h>  
int main()
{
	int *ptr, a=22;
	printf("Address of a:%u\n",&a);
	printf("Value of a:%d\n",a); 
	ptr=&a;
	printf("Address in pointer ptr:%u\n",ptr);
	printf("Content of pointer ptr:%d\n",*ptr); 
	a=11;  
	printf("Address in pointer ptr:%u\n",ptr);  
	printf("Content of pointer ptr:%d\n",*ptr);
	*ptr=2;	
	printf("Address of a:%u\n",&a); 
	printf("Value of a:%d\n",a);
	return 0;
}

Output:

Output

[Program Output]

Pointer to pointer:

As specified in the description, a pointer has the capability to hold the memory address of another pointer, at which point it is referred to as a double-pointer or pointer-to-pointer.

Syntax:

Example

Data_type **pointer_name;

Example program:

Example

#include<stdio.h>
int main()
{
    int a, *ptr1, **ptr2;
    a=65;
    ptr1=&a;
    ptr2=&ptr1;
    printf("a = %d\n", a);//65
    printf("address of a = %d\n", &a);//5000
    printf("ptr1 = %d\n", ptr1);//5000
    printf("address ptr1 = %d\n", &ptr1);//6000
    printf("*ptr1 = %d\n", *ptr1);//65
    printf("ptr2 = %d\n", ptr2);//6000
    printf("*ptr2 = %d\n", *ptr2);//5000
    printf("**ptr2 = %d\n", **ptr2);//65
}

Output:

Output

a = 65
address of a = 6487572
ptr1 = 6487572
address ptr1 = 6487560
*ptr1 = 65
ptr2 = 6487560
*ptr2 = 6487572
**ptr2 = 65

Pointer to Arrays

  • For an array, the base address of the array is the address where the very first element at the 0 th index is stored.
  • When we declare an array, the compiler allocates the memory to contain all the array elements and gives the base address.

Here, ptr refers to the pointer indicating the initial element of the array (arr[0]).

Points to understand:

For an array:

int arr[4], a pointer say ptr is pointing at arr[0], then:

  • &arr[0] is equivalent to ptr.
  • arr[0] is equivalent to *ptr.
  • &arr[1] is equivalent to ptr+1 and arr[1] is equivalent to *(ptr+1).
  • &arr[2] is equivalent to ptr+2 and arr[2] is equivalent to *(ptr+2).

Example program:

Example

#include <stdio.h>
int main() 
{
     int i, x[6], sum = 0;
     printf("Enter any six numbers: ");
     for(i = 0; i < 6; ++i) 
     {
          scanf("%d", x+i); // Equivalent to scanf("%d", &x[i]);
          sum += *(x+i);// Equivalent to sum += x[i]
      }
      printf("Sum = %d", sum);
      return 0;
}

Output:

Output

Enter 6 numbers: 2 3 4 5 6
0
Sum = 20

Understanding:

Here, x[6] represents the array that x points to by default, pointing to its initial address. Therefore, rather than using x[i], we can utilize x+i as explained earlier.

Using our own pointer to array:

Example

#include <stdio.h>
int main() 
{
  int arr[5] = {1, 2, 3, 4, 5};
  int* ptr;
  ptr = &arr[2];// ptr is assigned the address of the third element
  printf("*ptr = %d \n", *ptr);   //3
  printf("*(ptr+1) = %d \n", *(ptr+1));// 4
  printf("*(ptr-1) = %d", *(ptr-1));// 2
  return 0;
}

Output:

Output

*ptr = 3
*(ptr+1) = 4
*(ptr-1) = 2

Pointer as a Function argument

Pre-requisite: call by value (functions)

To transmit arguments from the function call to the function declaration, there are two methods available. The first method is call by value, where the actual values are passed. The second method, which is more efficient, is Call by Reference. In this approach, the addresses of the pointers are passed.

Example program:

Example

#include <stdio.h>
void swap(int *m, int *n);//Function definition
int main()
{
    int a = 10, b = 20;
    printf("a = %d\n", a);
    printf("b = %d\n\n", b);
    swap(&a, &b);//passing address in the function call
    printf("After Swapping:\n\n");
    printf("a = %d\n", a);
    printf("b = %d", b);
    return 0;
}
void swap(int *m, int *n) //Function declaration
{
	printf("\n*m and *n = %d and %d",*m,*n);
    int temp;
    temp = *m;
    *m = *n;
    *n = temp;
	printf("\nNow, *m = %d and *n = %d",*m,*n);
}

Output:

Output

a = 10
b = 20

*m and *n = 10 and 20
Now, *m = 20 and *n = 10

After Swapping:

a = 20
b = 10

Understanding:

Here, a function named "swap" has been created to interchange the values stored in two variables, "a" and "b". The initial values assigned to "a" and "b" are 10 and 20, respectively. The function is defined with two pointers, m and n. Subsequently, the addresses of these variables are passed as arguments to the pointer parameters. Therefore, in the function call, "&a" and "&b" are passed to m and n during the declaration. The value exchange is carried out by dereferencing the pointers.

  • When employing "call by value", any modifications made to the reference variable (parameters) do not impact the original variables (arguments).
  • In contrast, with "call by reference", alterations made to the reference variable directly influence the original variables.

This can be seen in the function definition. The values of m and n are altered alongside "a" and "b".

Pointer to Structure

Pre-requisite: Structures in C

When aiming to retrieve a member within a structure by referencing its variable, we employ the "." operator.

When a pointer of structure type is declared, the "->" operator is employed to retrieve the members within the structure.

Example:

Example

struct employee
{
   int age;
   float weight;
};
int main()
{
    struct employee *employeePtr, employee1;
}

Here,

The expression employeePtr -> age is equal to dereferencing the pointer using (*employeePtr).age.

Dereferencing the pointer employeePtr and accessing its weight member is the same as directly accessing (*employeePtr).weight.

Example program:

Example

#include <stdio.h>
struct student 
{
    char name[20];
    int number;
    int rank;
};
int main()
{
    struct student variable = {"Rishab", 100, 1};
    struct student *ptr;
    ptr = &variable;
    printf("NAME: %s\n", ptr->name);
    printf("NUMBER: %d\n", ptr->number);
    printf("RANK: %d", ptr->rank);
    return 0;
}

Output:

Output

NAME: Rishab
NUMBER: 100
RANK: 1

Self Referential Structure

These are the formations that include one or multiple pointers pointing to the same structure as their elements.

To clarify, structures that apply the same type of logic practice are known as "self-referential structures."

Example program:

Example

#include<stdio.h>
struct node { 
    int data1; 
    char data2; 
    struct node* link; 
}; 
int main() 
{ 
    struct node ob1; 
    ob1.link = NULL; 
    ob1.data1 = 10; 
    ob1.data2 = 20; 
    struct node ob2; 
    ob2.link = NULL; 
    ob2.data1 = 30; 
    ob2.data2 = 40; 
    ob1.link = &ob2; 
    printf("%d", ob1.link->data1); 
    printf("\n%d", ob1.link->data2); 
}

Output:

Features of Pointers

  • Saves memory space
  • Execution time is faster because of the directly accessed memory locations of the values.
  • Useful to represent multi-dimensional arrays and other data structures
  • Used for file handling
  • Efficient access to the memory-dynamic memory allocations.

What is the anticipated output of this program?

Example

#include<stdio.h>
int main()	
{
	 int i = 5;
 	void *vptr; 
 	vptr = &i;
 	printf("\nValue of vptr = %d ", *vptr);
 	return 0;
}

Solution:

Upon running, this code results in a compile-time error.

Example

error: invalid use of void expression

This is due to the fact that "vptr" is a pointer of type void. Dereferencing void pointers is not allowed directly. To access the value, a typecast is required before dereferencing the pointer.

Void pointer: A pointer lacking an associated data type.

  1. What is the expected output of this code snippet?
  2. Example
    
    #include<stdio.h>
    int main()
    {
    	int i = 3;
    	int *j;
    	int **k;
    	j = &i;
    	k = &j;
    	k++;
    	printf("%d ",**k);
    	return 0;
    }
    

Here, the variable k is a double pointer referring to "i" indirectly. However, upon incrementing k, the resulting value becomes a random value that does not correspond to any specific variable's address. Consequently, this situation may lead to a segmentation fault or printing of an arbitrary value.

  1. What is the expected output of this code?
  2. Example
    
    #include<stdio.h>
    int main()
    {
    	int i = 3;
    	int *j;
    	j = &i;
    	j++;
    	printf("%d ",*j);
    	return 0;
    }
    

Here, the pointer j points to i. However, in the subsequent step, j is increased. Consequently, j no longer holds any valid address or value. Instead, it contains a random value due to the lack of initialization to the memory location adjacent to variable "i".

  1. What variances exist between call by value and call by reference?
S. No Call by Value Call by reference
1. The copy of the argument in the function call is made into the parameters in the declaration, and the values are passed. Here, the address of the arguments is passed to the pointer-parameters in the function declaration, and hence the values are passed.
2. Changes in the function are restricted to the function only. The values of the actual parameters do not change. With the modifications inside the function, the actual parameters, as well as reference parameters all, are modified/
3. Actual and formal parameters belong to different memory locations Actual and formal parameters are created at the same memory space
  1. What are the most significant uses of pointers in any programming language?
  • For implementing dynamic memory allocation.
  • To implement different data structures.
  • To perform system-level programming.
  • To implement call-by-reference
  • For accessing array members without complex syntaxes and confusion.

Input Required

This code uses input(). Please provide values below: