void single pointers

In this section, you are going to learn about

What is the use of void pointers ?

How to use void pointers ?

void *ptr;

  • Single void pointer CAN NOT be dereferenced

 1#include <stdio.h>
 2
 3int main(void)
 4{
 5        int a = 5;
 6
 7        void *ptr;
 8
 9        ptr = (void *) &a;
10
11        printf("a = %d\n", *ptr);
12
13        return 0;
14}

In above code, Line 11 is NOT VALID

$ cc p1_void_sp.c

p1_void_sp.c: In function ;main:
p1_void_sp.c:11:21: warning: dereferencing "void *" pointer
   11 |  printf("a = %d\n", *ptr);
      |                     ^~~~
p1_void_sp.c:11:21: error: invalid use of void expression
  • void pointer MUST be typecasted to type of originial data before using

 1#include <stdio.h>
 2
 3int main(void)
 4{
 5        int a = 5;
 6
 7        void *ptr;
 8
 9        ptr = (void *) &a;
10
11        printf("a = %d\n", * (int *) ptr);
12
13        return 0;
14}
  • Note Line 11 in above code snippet. This is the right method to typecase and derefer

This is easy ! Just know the type of pointer assigned to void pointer !

  • Look at below examples

void pointer can hold the address of a character

  • Step 1 : Define a char

char a = 5;
  • Step 2 : Define a void pointer

void *ptr;
  • Step 3 : Assign address of char to void pointer

ptr = (void *) &a;

Note that,

typeof(ptr) is void *

typeof(&a) is char *

  • Step 4 : Derefer void pointer to access char

printf("a = %d\n", * (char *) ptr);
  • See full program below

 1#include <stdio.h>
 2
 3int main(void)
 4{
 5        char a = 5;
 6
 7        void *ptr;
 8
 9        ptr = (void *) &a;
10
11        printf("a = %d\n", * (char *) ptr);
12
13        return 0;
14}
  • Alternatively, you can use an extra pointer of type char *. See below

 1#include <stdio.h>
 2
 3int main(void)
 4{
 5        char a = 5;
 6
 7        void *ptr;
 8
 9        ptr = (void *) &a;
10
11        char *iptr;
12
13        iptr = (char *) ptr;
14
15        printf("a = %d\n", *iptr);
16
17        return 0;
18}

void pointer can hold the address of an integer

  • Step 1 : Define an integer

int a = 5;
  • Step 2 : Define a void pointer

void *ptr;
  • Step 3 : Assign address of int to void pointer

ptr = (void *) &a;

Note that,

typeof(ptr) is void *

typeof(&a) is int *

  • Step 4 : Derefer void pointer to access int

printf("a = %d\n", * (int *) ptr);
  • See full program below

 1#include <stdio.h>
 2
 3int main(void)
 4{
 5        int a = 5;
 6
 7        void *ptr;
 8
 9        ptr = (void *) &a;
10
11        printf("a = %d\n", * (int *) ptr);
12
13        return 0;
14}
  • Alternatively, you can use an extra pointer of type int *. See below

 1#include <stdio.h>
 2
 3int main(void)
 4{
 5        int a = 5;
 6
 7        void *ptr;
 8
 9        ptr = (void *) &a;
10
11        int *iptr;
12
13        iptr = (int *) ptr;
14
15        printf("a = %d\n", *iptr);
16
17        return 0;
18}

void pointer can hold the address of a structure

  • Step 1 : Define a Structure

struct ABC {
        int x;
        int y;
};

struct ABC a = { .x = 10, .y = 20 };
  • Step 2 : Define a void pointer

void *ptr;
  • Step 3 : Assign address of int to void pointer

ptr = (void *) &a;

Note that,

typeof(ptr) is void *

typeof(&a) is struct ABC *

  • Step 4 : Derefer void pointer to access members

printf("a.x = %d\n", ((struct ABC *) ptr)->x );
printf("a.y = %d\n", ((struct ABC *) ptr)->y );
  • See full program below

 1#include <stdio.h>
 2
 3struct ABC {
 4        int x;
 5        int y;
 6};
 7
 8int main(void)
 9{
10        struct ABC a = { .x = 10, .y = 20 };
11
12        void *ptr;
13
14        ptr = (void *) &a;
15
16        printf("a.x = %d\n", ((struct ABC *) ptr)->x );
17        printf("a.y = %d\n", ((struct ABC *) ptr)->y );
18
19        return 0;
20}
  • Alternatively, you can use an extra pointer of type struct ABC *. See below

 1#include <stdio.h>
 2
 3struct ABC {
 4        int x;
 5        int y;
 6};
 7
 8int main(void)
 9{
10        struct ABC a = { .x = 10, .y = 20 };
11
12        void *ptr;
13
14        ptr = (void *) &a;
15
16        struct ABC *sptr;
17
18        sptr = (struct ABC *) ptr;
19
20        printf("a.x = %d\n", sptr->x );
21        printf("a.y = %d\n", sptr->y );
22
23        return 0;
24}

void pointer can hold the address of a character array

  • Step 1 : Define a single dimension array of characters

char a[7] = "Laptop";
  • Step 2 : Define a void pointer and assign address of array to it

void *ptr;

ptr = (void *) a;
  • Step 3 : Access and Print the String : Typecasting method

printf("a = %s\n", (char *)ptr);
  • Step 4 : Access and Print the String : Separate pointer method

char *cptr;

cptr = (char *) ptr;

printf("a = %s\n", cptr);
  • Step 5 : Access and Print individual characters : Typecasting method

for (int i = 0; i < 7; i++)
{
        printf("%c", ((char *)ptr)[i] );
}
  • Step 6 : Access and Print individual characters : Separate pointer method

char *ch_ptr;

ch_ptr = (char *) ptr;

for (int i = 0; i < 7; i++)
{
        printf("%c", ch_ptr[i] );
}
  • See full program below

 1#include <stdio.h>
 2
 3int main(void)
 4{
 5        char a[7] = "Laptop";
 6
 7        void *ptr;
 8
 9        ptr = (void *) a;
10
11        // Method 1 : Print String : Use Typecasting
12        printf("a = %s\n", (char *)ptr);
13
14        // Method 2 : Print String : Use Seprate pointer
15        char *cptr;
16
17        cptr = (char *) ptr;
18
19        printf("a = %s\n", cptr);
20
21        // Method 1 : Print Character : Use Typecasting
22        for (int i = 0; i < 7; i++)
23        {
24                printf("%c", ((char *)ptr)[i] );
25        }
26
27        printf("\n");
28
29        // Method 2 : Print Character : Use Separate pointer
30        char *ch_ptr;
31
32        ch_ptr = (char *) ptr;
33
34        for (int i = 0; i < 7; i++)
35        {
36                printf("%c", ch_ptr[i] );
37        }
38
39        printf("\n");
40
41        return 0;
42}

void pointer can hold the address of an integer array

  • Step 1 : Define a single dimension array of integers

int a[7] = { 0, 1, 2, 3, 4, 5, 6 };
  • Step 2 : Define a void pointer and assign address of array to it

void *ptr;

ptr = (void *) a;
  • Step 3 : Access and Print individual integers : Typecasting method

for (int i = 0; i < 7; i++)
{
        printf("%d ", ((int *)ptr)[i] );
}
  • Step 4 : Access and Print individual integers: Separate pointer method

int *i_ptr;

i_ptr = (int *) ptr;

for (int i = 0; i < 7; i++)
{
        printf("%d ", i_ptr[i] );
}
  • See full program below

 1#include <stdio.h>
 2
 3int main(void)
 4{
 5        int a[7] = { 0, 1, 2, 3, 4, 5, 6 };
 6
 7        void *ptr;
 8
 9        ptr = (void *) a;
10
11        // Method 1 : Print Integers : Typecasting method
12        for (int i = 0; i < 7; i++)
13        {
14                printf("%d ", ((int *)ptr)[i] );
15        }
16
17        printf("\n");
18
19        // Method 2 : Print Integers : Separate Pointer method
20        int *i_ptr;
21
22        i_ptr = (int *)ptr;
23
24        for (int i = 0; i < 7; i++)
25        {
26                printf("%d ", i_ptr[i] );
27        }
28
29        printf("\n");
30
31        return 0;
32}
  • Output is as below

0 1 2 3 4 5 6
0 1 2 3 4 5 6

void pointer can hold the address of a structure array

  • Step 1 : Define a single dimension array of structures

struct ABC {
        int x;
        int y;
};

struct ABC a[3] = {
        { .x = 1, .y = 2 },
        { .x = 10, .y = 20 },
        { .x = 100, .y = 200 }
};
  • Step 2 : Define a void pointer and assign address of array to it

void *ptr;

ptr = (void *) a;
  • Step 3 : Access and Print individual structures : Typecasting method

for (int i = 0; i < 3; i++)
{
        printf("a[%d].x = %d\t", i, ((struct ABC *)ptr)[i].x );
        printf("a[%d].y = %d ", i, ((struct ABC *)ptr)[i].y );
        printf("\n");
}
  • Step 4 : Access and Print individual structures : Separate pointer method

struct ABC *s_ptr;

s_ptr = (struct ABC *) ptr;

for (int i = 0; i < 3; i++)
{
        printf("a[%d].x = %d\t", i, s_ptr[i].x );
        printf("a[%d].y = %d ", i, s_ptr[i].y );
        printf("\n");
}
  • See full program below

 1#include <stdio.h>
 2
 3struct ABC {
 4        int x;
 5        int y;
 6};
 7
 8int main(void)
 9{
10        struct ABC a[3] = {
11                { .x = 1, .y = 2 },
12                { .x = 10, .y = 20 },
13                { .x = 100, .y = 200 }
14        };
15
16        void *ptr;
17
18        ptr = (void *) a;
19
20        // Method 1 : Print Integers : Typecasting method
21        for (int i = 0; i < 3; i++)
22        {
23                printf("a[%d].x = %d\t", i, ((struct ABC *)ptr)[i].x );
24                printf("a[%d].y = %d ", i, ((struct ABC *)ptr)[i].y );
25                printf("\n");
26        }
27
28        printf("\n");
29
30        // Method 2 : Print Integers : Separate Pointer method
31        struct ABC *s_ptr;
32
33        s_ptr = (struct ABC *) ptr;
34
35        for (int i = 0; i < 3; i++)
36        {
37                printf("a[%d].x = %d\t", i, s_ptr[i].x );
38                printf("a[%d].y = %d ", i, s_ptr[i].y );
39                printf("\n");
40        }
41
42        printf("\n");
43
44        return 0;
45}

void pointer can be passed as an argument to a function (By Value)

  • Step 1 : Define an Integer

int a = 5;
  • Step 2 : Define a void pointer and assign address of integer

void *ptr;

ptr = (void *) &a;
  • Step 3 : Pass ptr as call by Value to function fun

fun(ptr);
  • Step 4 : Define function fun. Note the prototype !

void fun(void *p)
{

}
  • Step 5 : Derefer and access integer inside function fun

void fun(void *p)
{
        int *iv;

        iv = (int *) p;

        printf("a = %d\n", *iv);
}
  • See full program below

 1#include <stdio.h>
 2
 3void fun(void *p)
 4{
 5        int *iv;
 6
 7        iv = (int *) p;
 8
 9        printf("a = %d\n", *iv);
10}
11
12int main(void)
13{
14        int a = 5;
15
16        void *ptr;
17
18        ptr = (void *) &a;
19
20        fun(ptr);
21
22        return 0;
23}

void pointer can be passed as an argument to a function (By Reference)

  • Step 1 : Define an Integer

int a = 5;
  • Step 2 : Define a void pointer and assign address of integer

void *ptr;

ptr = (void *) &a;
  • Step 3 : Pass ptr as call by Reference to function fun

fun(&ptr);
  • Step 4 : Define function fun. Note the prototype !

void fun(void **p)
{

}
  • Step 5 : Derefer and access integer inside function fun

void fun(void **p)
{
        int *iv;

        iv = (int *) *p;

        printf("a = %d\n", *iv);
}
  • See full program below

 1#include <stdio.h>
 2
 3void fun(void **p)
 4{
 5        int *iv;
 6
 7        iv = (int *) *p;
 8
 9        printf("a = %d\n", *iv);
10}
11
12int main(void)
13{
14        int a = 5;
15
16        void *ptr;
17
18        ptr = (void *) &a;
19
20        fun(&ptr);
21
22        return 0;
23}

void pointer can be used as part of an expression

  • Step 1 : Define an Integer

int a = 10;
  • Step 2 : Define a void pointer ptr and assign address of integer to it

void *ptr;

ptr = (void *) &a;
  • Step 3 : Derefer void pointer ptr and use in an expression

sum = *(int *)ptr + b + c;

This is also same as

sum = a + b + c;
  • See full program below

 1#include <stdio.h>
 2
 3int main(void)
 4{
 5        int a = 10;
 6        int b = 20;
 7        int c = 30;
 8
 9        int sum;
10
11        void *ptr;
12
13        ptr = (void *) &a;
14
15        sum = a + b + c;
16
17        printf("sum = %d\n", sum);
18
19        sum = *(int *)ptr + b + c;
20
21        printf("sum = %d\n", sum);
22
23        return 0;
24}

void pointer can point to heap allocated memory

  • Step 1 : Define a void pointer ptr

void *ptr;
  • Step 2 : Allocate memory from heap and assign to ptr

ptr = malloc(40);
  • Step 3 : Assign void pointer to an integer pointer

int *iptr;

iptr = (int *) ptr;
  • Step 4 : Write : Use iptr to write to Heap memory

for (int i = 0; i < 10; i++)
{
        iptr[i] = ++count;
}
  • Step 5 : Read : Use iptr to read from Heap memory

for (int i = 0; i < 10; i++)
{
        printf("%d\n", iptr[i]);
}
  • See full program below

 1#include <stdio.h>
 2#include <stdlib.h>
 3
 4int main(void)
 5{
 6        void *ptr;
 7
 8        ptr = malloc(40);
 9
10        int *iptr;
11
12        iptr = (int *) ptr;
13
14        int count = 0;
15
16        for (int i = 0; i < 10; i++)
17        {
18                iptr[i] = ++count;
19        }
20
21        for (int i = 0; i < 10; i++)
22        {
23                printf("%d\n", iptr[i]);
24        }
25
26        free(ptr);
27
28        return 0;
29}

We can define an Array of void pointers

  • Step 1 : Define an array of void pointers

void *ptr[4];
  • Step 2 : Assign individual void pointers

int a = 10;
char b = 20;
struct ABC c = { .x = 30, .y = 40 };
struct ABC d = { .x = 50, .y = 60 };

ptr[0] = (void *) &a;
ptr[1] = (void *) &b;
ptr[2] = (void *) &c;
ptr[3] = (void *) &d.x;
  • Step 3 : Use the void pointers in an expression. Remember to Typecast and Derefer !

sum =   *(int *)ptr[0]  +
        *(char *)ptr[1] +
        ((struct ABC *)ptr[2]) -> x +
        ((struct ABC *)ptr[2]) -> y +
        *(int *)ptr[3];

This is same as

sum = a + b + c.x + c.y + d.x;
  • See full program below

 1#include <stdio.h>
 2
 3struct ABC {
 4        int x;
 5        int y;
 6};
 7
 8int main(void)
 9{
10        int a = 10;
11        char b = 20;
12        struct ABC c = { .x = 30, .y = 40 };
13        struct ABC d = { .x = 50, .y = 60 };
14
15        void *ptr[4];
16
17        ptr[0] = (void *) &a;
18        ptr[1] = (void *) &b;
19        ptr[2] = (void *) &c;
20        ptr[3] = (void *) &d.x;
21
22        int sum;
23
24        sum =   *(int *)ptr[0]  +
25                *(char *)ptr[1] +
26                ((struct ABC *)ptr[2]) -> x +
27                ((struct ABC *)ptr[2]) -> y +
28                *(int *)ptr[3];
29
30        printf("sum = %d\n", sum);
31
32        return 0;
33}

Array of void pointers can be passed as an argument to a function (By Value)

  • Step 1 : Define an array of void pointers

void *ptr[4];
  • Step 2 : Assign individual void pointers

int a = 10;
char b = 20;
struct ABC c = { .x = 30, .y = 40 };
struct ABC d = { .x = 50, .y = 60 };

ptr[0] = (void *) &a;
ptr[1] = (void *) &b;
ptr[2] = (void *) &c;
ptr[3] = (void *) &d.x;
  • Step 3 : Pass array of void pointers by Value to function fun

fun(ptr);
  • Step 4 : Define the function fun

void fun(void *p[4])
{

}
  • Step 5 : Use the void pointers in an expression. Remember to Typecast and Derefer !

void fun(void *p[4])
{
        int sum;

        sum =   *(int *)p[0]  +
                *(char *)p[1] +
                ((struct ABC *)p[2]) -> x +
                ((struct ABC *)p[2]) -> y +
                *(int *)p[3];

        printf("sum = %d\n", sum);
}
  • See full program below

 1#include <stdio.h>
 2
 3struct ABC {
 4        int x;
 5        int y;
 6};
 7
 8void fun(void *p[4])
 9{
10        int sum;
11
12        sum =   *(int *)p[0]  +
13                *(char *)p[1] +
14                ((struct ABC *)p[2]) -> x +
15                ((struct ABC *)p[2]) -> y +
16                *(int *)p[3];
17
18        printf("sum = %d\n", sum);
19}
20
21int main(void)
22{
23        int a = 10;
24        char b = 20;
25        struct ABC c = { .x = 30, .y = 40 };
26        struct ABC d = { .x = 50, .y = 60 };
27
28        void *ptr[4];
29
30        ptr[0] = (void *) &a;
31        ptr[1] = (void *) &b;
32        ptr[2] = (void *) &c;
33        ptr[3] = (void *) &d.x;
34
35        fun(ptr);
36
37        return 0;
38}

Array of void pointers can be passed as an argument to a function (By Reference)

  • Step 1 : Define an array of void pointers

void *ptr[4];
  • Step 2 : Assign individual void pointers

int a = 10;
char b = 20;
struct ABC c = { .x = 30, .y = 40 };
struct ABC d = { .x = 50, .y = 60 };

ptr[0] = (void *) &a;
ptr[1] = (void *) &b;
ptr[2] = (void *) &c;
ptr[3] = (void *) &d.x;
  • Step 3 : Pass array of void pointers by Reference to function fun

fun(&ptr);
  • Step 4 : Define the function fun

void fun(void * (*p) [4])
{

}
  • Step 5 : Use the void pointers in an expression. Remember to Typecast and Derefer !

void fun(void * (*p) [4])
{
        int sum;

        sum =   *(int *)(*p)[0]  +
                *(char *)(*p)[1] +
                ((struct ABC *)(*p)[2]) -> x +
                ((struct ABC *)(*p)[2]) -> y +
                *(int *)(*p)[3];

        printf("sum = %d\n", sum);
}
  • See full program below

 1#include <stdio.h>
 2
 3struct ABC {
 4        int x;
 5        int y;
 6};
 7
 8void fun(void * (*p) [4])
 9{
10        int sum;
11
12        sum =   *(int *)(*p)[0]  +
13                *(char *)(*p)[1] +
14                ((struct ABC *)(*p)[2]) -> x +
15                ((struct ABC *)(*p)[2]) -> y +
16                *(int *)(*p)[3];
17
18        printf("sum = %d\n", sum);
19}
20
21int main(void)
22{
23        int a = 10;
24        char b = 20;
25        struct ABC c = { .x = 30, .y = 40 };
26        struct ABC d = { .x = 50, .y = 60 };
27
28        void *ptr[4];
29
30        ptr[0] = (void *) &a;
31        ptr[1] = (void *) &b;
32        ptr[2] = (void *) &c;
33        ptr[3] = (void *) &d.x;
34
35        fun(&ptr);
36
37        return 0;
38}

void pointers can be defined inside a structure

  • Step 1 : Define a structure struct ABC with a void pointer

struct ABC {
        int a;
        int b;
        int c;
        void *pqr_ptr;
};
  • Step 2 : Define a structure struct PQR

struct PQR {
        int p;
        int q;
        int r;
};
  • Step 3 : Define structue objects for struct ABC and struct PQR

struct ABC abc = {.a = 10, .b = 20, .c = 30 };

struct PQR pqr = {.p = 100, .q = 200, .r = 300 };
  • Step 4 : Assign void pointer inside struct ABC with address of struct PQR

abc.pqr_ptr = (void *) &pqr;
  • Step 5 : Assign void pointer ptr with address of struct ABC

ptr = (void *) &abc;
  • Step 6 : Pass ptr by Value to function fun

fun(ptr);
  • Step 7 : Define the function fun

void fun(void *ptr)
{

}
  • Step 8 : Use void pointers inside function fun. Typecast and Derefer

void fun(void *ptr)
{
        struct ABC *abc_p;
        struct PQR *pqr_p;
        int sum;

        abc_p = (struct ABC *)ptr;
        pqr_p = (struct PQR *)abc_p->pqr_ptr;

        sum = abc_p->a +  abc_p->b +  abc_p->c ;

        sum += pqr_p->p + pqr_p->q + pqr_p->r;

        printf("sum = %d\n", sum);
}
  • See full program below

 1#include <stdio.h>
 2
 3struct PQR {
 4        int p;
 5        int q;
 6        int r;
 7};
 8
 9struct ABC {
10        int a;
11        int b;
12        int c;
13        void *pqr_ptr;
14};
15
16void fun(void *ptr)
17{
18        struct ABC *abc_p;
19        struct PQR *pqr_p;
20        int sum;
21
22        abc_p = (struct ABC *)ptr;
23        pqr_p = (struct PQR *)abc_p->pqr_ptr;
24
25        sum = abc_p->a +  abc_p->b +  abc_p->c ;
26
27        sum += pqr_p->p + pqr_p->q + pqr_p->r;
28
29        printf("sum = %d\n", sum);
30}
31
32int main(void)
33{
34        struct ABC abc = {.a = 10, .b = 20, .c = 30 };
35
36        struct PQR pqr = {.p = 100, .q = 200, .r = 300 };
37
38        abc.pqr_ptr = (void *) &pqr;
39
40        void *ptr;
41
42        ptr = (void *) &abc;
43
44        fun(ptr);
45
46        return 0;
47}

Learnings

Single void pointer CAN NOT be dereferenced directly without explicit typecast

Single void pointer CAN HOLD the address of a character

Single void pointer CAN HOLD the address of an integer

Single void pointer CAN HOLD the address of a structure

Single void pointer CAN HOLD the address of a character array

Single void pointer CAN HOLD the address of an integer array

Single void pointer CAN HOLD the address of a structure array

Single void pointer CAN BE passed by value to a function

Single void pointer CAN BE passed by reference to a function

Single void pointer CAN BE used in an expression with explicit typecasting

Single void pointer CAN POINT to memory block in Heap

Array of Single void pointers CAN BE defined which can hold addresses of heterogeneous types

Array of Single void pointers CAN BE passed by value to a function

Array of Single void pointers CAN BE passed by reference to a function

Single void pointers CAN BE used as structure members