Pointers in C (original) (raw)

A pointer is a variable that stores the memory address of another variable. Instead of holding a direct value, it holds the address where the value is stored in memory. It is the backbone of low-level memory manipulation in C.

#include <stdio.h>

int main() {

// Normal Variable
int var = 10;

// Pointer Variable ptr that stores address of var
int *ptr = &var;

// Directly accessing ptr will give us an address
printf("%p", ptr);

return 0;

}

`

This hexadecimal integer (starting with 0x) is the memory address.

Let us understand different steps of the above program.

**Initialize the Pointer

Dereference a Pointer

We have to first **dereference the pointer to access the value present at the memory address. This is done with the help of **dereferencing operator(*) (same operator used in declaration).

C `

#include <stdio.h>

int main() { int var = 10;

// Store address of var variable
int* ptr = &var;

// Dereferencing ptr to access the value
printf("%d", *ptr);

return 0;

}

`

**Note: Earlier, we used %d for printing pointers, but C provides a separate format specifier ****%p** for printing pointers.

Size of Pointers

The size of a pointer in C depends on the architecture (bit system) of the machine, not the data type it points to.

The size remains constant regardless of the data type (int*, char*, float*, etc.). We can verify this using the sizeof operator.

C `

#include <stdio.h>

int main() { int *ptr1; char *ptr2;

// Finding size using sizeof()
printf("%zu\n", sizeof(ptr1));
printf("%zu", sizeof(ptr2));

return 0;

}

`

The reason for the same size is that the pointers store the memory addresses, no matter what type they are. As the space required to store the addresses of the different memory locations is the same, the memory required by one pointer type will be equal to the memory required by other pointer types.

**Note: The actual size of the pointer may vary depending on the **compiler and system architecture, but it is always **uniform across all data types on the same system.

Special Types of Pointers

There are 4 special types of pointers that used or referred to in different contexts:

**NULL Pointer

#include <stdio.h>

int main() { // Null pointer int *ptr = NULL;

return 0;

}

`

**Void Pointer

#include <stdio.h>

int main() { // Void pointer void *ptr;

return 0;

}

`

**Wild Pointers

The wild pointers are pointers that have not been initialized with something yet. These types of C-pointers can cause problems in our programs and can eventually cause them to crash. If values are updated using wild pointers, they could cause data abort or data corruption.

C `

#include <stdio.h>

int main() {

// Wild Pointer
int *ptr;

return 0;

}

`

Dangling Pointer

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

int main() { int* ptr = (int*)malloc(sizeof(int));

// After below free call, ptr becomes a dangling pointer
free(ptr);
printf("Memory freed\n");

// removing Dangling Pointer
ptr = NULL;

return 0;

}

`

**C Pointer Arithmetic

The pointer arithmetic refers to the arithmetic operations that can be performed on a pointer. It is slightly different from the ones that we generally use for mathematical calculations as only a limited set of operations can be performed on pointers. These operations include:

**Constant Pointers

In **constant pointers, the memory address stored inside the pointer is constant and cannot be modified once it is defined. It will always point to the same memory address.

C `

#include <stdio.h>

int main() { int a = 90; int b = 50;

// Creating a constant pointer
int* const ptr = &a;

// Trying to reassign it to b
ptr = &b;

return 0;

}

`

**Output

solution.c: In function ‘main’:
solution.c:11:9: error: assignment of read-only variable ‘ptr’
11 | ptr = &b;
| ^

As we try here to assign ptr a new address, the compiler throws an error because a constant pointer cannot change the memory location it was originally assigned.
We can also create a pointer to constant or even constant pointer to constant. Refer to this article to know more - Constant pointer, Pointers to Constant and Constant Pointers to Constant

Pointer to Function

A **function pointer is a type of pointer that stores the address of a function, allowing functions to be passed as arguments and invoked dynamically. It is useful in techniques such as callback functions, event-driven programs.

C `

#include <stdio.h>

int add(int a, int b) { return a + b; }

int main() {

// Declare a function pointer that matches
  // the signature of add() function
int (*fptr)(int, int);

// Assign address of add()
fptr = &add;

// Call the function via ptr
printf("%d", fptr(10, 5));

return 0;

}

`

**Multilevel Pointers

In C, we can create **multi-level pointers with any number of levels such as – ***ptr3, ****ptr4, ******ptr5 and so on. Most popular of them is **double pointer (pointer to pointer). It stores the memory address of another pointer. Instead of pointing to a data value, they point to another pointer.

C `

#include <stdio.h>

int main() { int var = 10;

// Pointer to int
int *ptr1 = &var;

// Pointer to pointer (double pointer)
int **ptr2 = &ptr1;  

// Accessing values using all three
printf("var: %d\n", var);          
printf("*ptr1: %d\n", *ptr1);
printf("**ptr2: %d", **ptr2);

return 0;

}

`

Output

var: 10 *ptr1: 10 **ptr2: 10

Advantages of Pointers

Following are the major advantages of pointers in C:

Issues with Pointers

Pointers are vulnerable to errors and have following disadvantages:

Read about Difference between Pointers and Arrays.