void pointer in c

void pointer in C/C++, you should know

In this article, we will learn what is void pointer in C and how we can use void pointer in our C code. If you are new in c programming, you should read this article “C pointer concept“. In the C language pointer is used to store the address of any variable or function but we need to remember that types of the pointer should be the same as the types of the pointed object (variable, pointer, array, function …etc.).

For example, if you want to store the address of the character, the pointer should be a pointer to the character.

char cData;

char *pcData = NULL;

pcData = &cData;

 

To resolve the above problem, C language introduces a generic type of pointer (void pointer) that can store the address of any type.

 

What is void pointer in C?

A void pointer in c is called a generic pointer, it has no associated data type. It can store the address of any type of object and it can be type-casted to any type. According to C standard, the pointer to void shall have the same representation and alignment requirements as a pointer to a character type. A void pointer declaration is similar to the normal pointer, but the difference is that instead of data types we use the void keyword.

Syntax:

void * Pointer_Name;

Example,

void *pvHandle;

 

 

What is the size of a void pointer in C?

The size of a void pointer is similar to the size of the character pointer. According to C standard, the pointer to void shall have the same representation and alignment requirements as a pointer to a character type.

The size of the pointers depending on the platform and it can be 2bytes, 4bytes or 8bytes …etc.

Let’s see some example code.
#include <stdio.h>

int main(int argc, char *argv[])
{

    void *pvData = NULL; //void pointer

    int *iData  = NULL;// integer pointer

    char *cData = NULL;//character pointer

    float *fData = NULL;//float pointer



    //size of void pointer
    printf("size of void pointer = %d\n\n",sizeof(pvData));


    //size of void pointer
    printf("size of integer pointer = %d\n\n",sizeof(iData));

    //size of void pointer
    printf("size of character pointer = %d\n\n",sizeof(cData));

    //size of void pointer
    printf("size of float pointer = %d\n\n",sizeof(fData));

    return 0;
}

Output: On a 32-bit machine

size of void pointer = 4

size of integer pointer = 4

size of character pointer = 4

size of float pointer = 4

 

 

Dereferencing a void pointer in C

Using the indirection operator (*) we can get back the value which is pointed by the pointer, but in case of void pointer we cannot use the indirection operator directly. This is because a void pointer has no data type that creates a problem for the compiler to predict the size of the pointed object. So before dereferencing the void * we have to typecast it, it enables the compiler to predict the data types.

Let’s see some example code.
#include <stdio.h>

int main(int argc, char *argv[])
{

    void *pvData;

    int iData = 10;


    pvData = &iData;

    printf("*pvData = %d",*pvData);

    return 0;

}

Explanation: When we compile the above code, we will get the compiler error because in the above code I tried to dereference the void pointer without type casing.

But what happened if we type-cast the void pointer, its working fine see the below example code.

#include <stdio.h>

int main(int argc, char *argv[])
{

    void *pvData;

    int iData = 10;


    pvData = &iData;

    printf("iData = %d",*(int*)pvData);

    return 0;
}

Output: 10

In the above code void pointer, pvData is pointing to the address of iData (integer variable). So to access the value of integer variable (iData) through the void pointer we have to typecast void pointer through the integer pointer.

(int *)pvData;

Now above expression behave like an integer pointer. You already know how to dereference an integer pointer using an indirection operator (*).

*(int *)pvData

Now you will get the value of the integer which addresses pointed by the void pointer.

 

 

Why are void pointers use?

A very important feature of the void pointer is reusability. Using the void pointer we can store the address of any object and whenever required we can get back the object through the indirection operator with proper casting.

Let’s take an example,
#include <stdio.h>

int main(int argc, char *argv[])
{

    void *pvData;

    int iData = 10;
    char cData = 'A';
    float fData = 27.6;

    //Assigning address of character
    pvData = &cData;

    //dereferencing void pointer with character typecasting
    printf("cData = %c\n\n",*((char*)pvData));



    //Assigning address of integer
    pvData = &iData;

    //dereferencing void pointer with integer typecasting
    printf("iData = %d\n\n",*((int *)pvData));



    //Assigning address of float
    pvData = &fData;

    //dereferencing void pointer with float typecasting
    printf("fData = %f\n\n",*((float *)pvData));

    return 0;
}

Output:

cData = A

iData = 10

fData = 27.600000

 

Explanation: In the above code, pvData is a void pointer. Using it I am storing the address of the different variables (float, int, and char) and after that getting back their values using the indirection operator and proper typecasting.

You can see in the example code, how a single pointer is dealing with different types of variables. This is a very interesting feature of the void pointer that makes the programmer helpless to use the void pointer.

 

If you want to learn more about the c language, here 10 Free days (up to 200 minutes) C video course for you.

C tutorial

Arithmetic operation on void pointers

Here I want to mention an important point about the arithmetic operation on a void pointer. If you will directly perform an arithmetic operation on the void pointer you may get unexpected results. So you should perform proper typecasting on the void pointer before performing the arithmetic operation.

#include<stdio.h>

int main()
{
    //integer array
    int aiData[3] = {100, 200,300};

    //assigned first element address to the void pointer
    void *pvData = &aiData[0];

    printf(" pvData = %lu\n", pvData);

    printf(" pvData+1 = %lu\n", pvData +1); //Incorrect

    return 0;
}

 

When you will run the above code you will get the unexpected result.

 

Since the array (aiData) is the collection of integer element so the type of &aiData[0] would be a pointer to int (int*). So we have to typecast the void pointer pvData from the pointer to int (int*) before performing an arithmetic operation.

#include<stdio.h>

int main()
{
    //integer array
    int aiData[3] = {100, 200,300};

    //assigned first element address to the void pointer
    void *pvData = &aiData[0];

    printf(" pvData = %lu\n", pvData);

    printf(" pvData+1 = %lu\n", (int*)pvData +1); //Correct

    return 0;
}

Output:

void Arithmetic

You can see, showing the correct value. In my case, the integer size is 4 byte.

 

Application of void pointer in C 

Application of void pointers are very wide, we can not cover all the application in one article. Here I am taking one of the most popular applications of the void pointer in qsort function.

A qsort is a C standard library function that is used to sort arrays. Using the qsort function, we can sort the array of integer, double, long, etc.

Following is the declaration for qsort() function,

void qsort(void *arr, size_t elements, size_t size, int (*comp)(const void *, const void*));

Parameters of qsort:

arr − pointer to the first element of the array.

elements  − number of elements in the array.

size − size(in bytes) of the element in the array.

comp − compare function that is used to compares two elements.
int comp(const void* a, const void* b);

Let see an example code to understand the working of qsort and importance of void pointer:

In this example code, I am showing how is the qsort function sort any type of array with the help of compare function.

#include <stdio.h>

#define ELEMENT_SIZE(x)  sizeof(x[0])
#define ARRAY_SIZE(x)  (sizeof(x)/sizeof(x[0]))


//compare function for intger array
int compareInt(const void *a, const void *b)
{
    int x = *(const int *)a;
    int y = *(const int *)b;

    if (x < y)
        return -1;  //-1 for ascending, 1 for descending order.
    else if (x > y)
        return 1;   //1 for ascending, -1 for descending order.

    return 0;
}

//compare function for float array
int compareFloat(const void *a, const void *b)
{
    float x = *(const float *)a;
    float y = *(const float *)b;

    if (x < y)
        return -1;  //-1 for ascending, 1 for descending order.
    else if (x > y)
        return 1;   //1 for ascending, -1 for descending order.

    return 0;
}

int main(int argc, char *argv[])
{
    //Integer array
    int iData[] = { 40, 10, 100, 90, 20, 25 };

    //float array
    float fData[] = {1.2,5.7,78,98.5,45.67,81.76};
    //array index
    int index = 0;

    //sorting integer array
    qsort(iData,ARRAY_SIZE(iData),ELEMENT_SIZE(iData),compareInt);
    for (index=0; index<ARRAY_SIZE(iData); index++)
    {
        printf ("%d ",iData[index]);
    }

    printf("\n\n");
    //sortig float array
    qsort(fData,ARRAY_SIZE(fData),ELEMENT_SIZE(fData),compareFloat);
    for (index=0; index<ARRAY_SIZE(fData); index++)
    {
        printf ("%f ",fData[index]);
    }

    return 0;
}

Output:

10 20 25 40 90 100

1.200000 5.700000 45.669998 78.000000 81.760002 98.500000

 

 

Disadvantages of the void pointer in C

  • Like the other pointers, we cannot dereference the void pointers because the compiler does not have any information about the pointed object. If we try to compile the below code then we will get the compiler error.
#include<stdio.h>

int main()
{
    int iData = 100;
    
    void *piData = &iData;
    
    printf("%d", *piData);
    
    return 0;
}

 

But with proper typecasting, we can dereference the void pointer and get back the value of the pointed address.

#include<stdio.h>

int main()
{
    int iData = 1000;
    void *piData = NULL;
    
    piData = &iData;
    
    printf("%d", (*(int*)piData));
    
    return 0;
}
  • According to c standard arithmetic operation on void pointers is illegal that means the C standard doesn’t allow pointer arithmetic with void pointers. However, In GNU C, addition and subtraction operations are supported on void pointers to assuming the size of the void is 1.
#include<stdio.h>
int main()
{
    int aiData[3] = {100, 200,300};

    void *pvData = &aiData[1]; //address of 200

    pvData += sizeof(int);

    printf("%d", *(int *)pvData);

    return 0;
}

Output: 300 or compiler error.

Explanation: When we compile the code then some compiler throw the compiler error but some compiler compiled the code and print 300 as output to assume the size of the void 1.

Note: Don’t perform the arithmetic operation on the void pointer. As per the C standard sizeof is not applicable on void but in GNU C we can calculate the size of the void and sizeof operator return 1.

 

Advantages of the void pointer in c

  • Using the void pointer we can create a generic function that can take arguments of any data type. The memcpy and memmove library function are the best examples of the generic function, using these function we can copy the data from the source to destination.

Below code shows the implementation of memcpy in C

int Memcpy(void* dst, const void* src, unsigned int cnt)
{
    uint8_t *pszDest = (uint8_t *)dst;

    const uint8_t *pszSource =( const uint8_t*)src;

    while(cnt)
    {
        *(pszDest++)= *(pszSource++);
        cnt--;
    }

    return 0;
}

 

Using the memcpy we can copy the string, as well as the array of integers, see the below example codes.

#include<stdio.h>

int main()
{
    char *pszMessage  = "Welcome to aticleworld!";//Source String

    char aszDisplayMessage[32]= {0}; //Destination string

    short siLenString=0;  //

    siLenString = strlen(pszMessage)+1; // length of source string

    Memcpy(aszDisplayMessage, pszMessage,siLenString );//copy source to destination

    printf("Message = %s\n", aszDisplayMessage);

    return 0;
}

 

#include<stdio.h>

int main(void)
{

    int iLoop = 0;
    int aiSrc [5]  = {100,200,300,400,500};//integer array
    int aiDst[5]= {0}; //Destination array

    Memcpy(aiDst, aiSrc,sizeof(aiSrc));//copy integer array

    for(iLoop =0; iLoop <5 ; iLoop++) //print
    {
        printf("%d ",aiDst[iLoop]);
    }
    return 0;
}

 

You can see how memcpy is working here as a generic copy function with the help of a void pointer.

 

You want to learn more about C Pointers, you can check the below articles.