void pointers

Void Pointer in C Programming : Advantages & Pitfalls

Table of Contents
    Add a header to begin generating the table of contents

    Introduction

    In C programming, pointers are an important topic, which plays a crucial role in memory management and data manipulation. As the definition goes, a pointer is a variable that stores the memory address of another variable, and plays an important role in domains like Embedded Systems.

     

    Instead of directly holding the actual value, a pointer points to the location where the data is stored in the computer’s memory. In C programming, the void data type is unique, having a special purpose associated with it. It actually indicates the absence of any type.

     

    The Void type can be applied to data variables, function return type, and pointers. Void pointer in C example acts as a placeholder where no data type is needed. In case of pointers, the void pointers are also known as generic pointers. Unlike regular pointers that point to specific data types, a void pointer in C points to data of any type.

     

    In this blog post, let us learn about the basics of void pointer in C with examples and three use cases where void pointers and its generic nature comes in handy 

    Definition of Void Pointers

    Void pointers, often referred to as “void pointer in C,” are a special type of pointers in programming that can point to any data type. For example, imagine you have a storage room filled with various items such as books, toys, and gadgets. To manage the room efficiently, you decide to use a single box that can hold anything.

     

    This versatile box, is like a void pointer in C programming, allows you to point to a book, a toy, or a gadget, all within the same container. Similarly, in programming, you might encounter different data types like integers, floats, or characters, and you need a way to handle them together.

     

    Here’s where the magic of a void pointer in C comes into play. Instead of utilizing separate pointers for each data type, you can employ a void pointer. It functions as a mystery box that can hold any data type, enabling you to handle diverse information in a more flexible and convenient manner.

     

    So, when you encounter situations where you need to work with various data types seamlessly, the versatility of a void pointer in C becomes indispensable.

    Declaration of Void Pointers

    Void Pointers in C: The declaration of a void pointer follows the pattern void pointerName, where pointerName is the name of the pointer. The asterisk symbol indicates that it is a pointer.

    Void Pointer Syntax

    As mentioned in the definition of Void Pointers in C, in the above-mentioned example, the *vptr can be used to point to any type of data-type. A sample image is given below.

    Fig1 : Void Pointer Example in C

    Three Use Cases of Void Pointers

    Now that we understand the definition and declaration of a void pointer, let us understand three use cases for how this can be used in real-time implementation.

    1. Referencing and De-referencing the Void Pointers

    Referencing a void pointers in C means assigning it the memory address of a variable or an object. Since void pointers can point to any data type, you can reference them to point to integers, floats, characters, or even custom data structures. This we have already explained in Fig-2 mentioned above. 

     

    Dereferencing a void pointer means accessing the value stored at the memory address it points to. However, since void pointers don’t have a specific type, you cannot directly dereference them. You need to typecast them before dereferencing. 

    In order to explain how void pointers can be referenced and De-referenced, let’s take a small sample code as shown below in Fig. 1.

    Void Pointer in C example
    Fig 2 : Referencing & De-referencing of the Void Pointers in C

    From the above figure, it is clear that while referencing the void *, there is no need to typecast, only when dereferencing the void *, it needs to be type-casted otherwise, the gcc compiler will give a warning along with an error note, as shown in the figure below.

    Output : 

    Pointer Illustration
    Fig 3 : Result Obtained While Dereferencing the Void Pointer Without Typecasting.
    Pointer Illustration
    Fig 4 : Output after Typecasting the Void Pointer While Dereferencing

    In summary, we can say the void pointer can be referenced to any data type. There will not be any compilation errors. However, during dereferencing, it has to be type-cast into the appropriate data type. This also gives the pointer an indication of how many continuous bytes it needs to read from memory.

    2. Pointer Arithmetic in Void Pointer

    The pointer arithmetic works differently in a void pointer. As a developer, you need to take additional care when it comes to, say, incrementing a void pointer in C. This is mainly because the void pointer can point to any data type, and incrementing it should move the pointer by N bytes, where N is the size of the data type the pointer is pointing to. 

     

    Assume an integer pointer ptr which is pointing to an integer variable X. When ptr is incremented by doing a post increment operation (i.e  ptr++), it will advance by 4 bytes in the memory, assuming the size of the integer is 4 bytes. The same thing can be applied to character pointers or pointers of any data type. 

     

    Since you don’t know the size of the data type the void pointer is pointing to, blindly incrementing it will give incorrect output. Let us explain this with an example. Consider the code snippet given below.

    Void Pointer in C
    Fig 5 : Arithmetic Void Pointers in C - Example

    As you can see, the goal of the function display() is to print the array index, the memory address and the value that particular array index is holding. 

     

    In this case the array index is holding an integer value, hence you were expecting the function to print the values as 10,20,30,40,50. However when you actually execute this program you get a different output as follows.

    Output : 

    Pointer Illustration
    Fig 6 : Output for Code Giving Unexpected Result

    From the above result, one can see that we are not getting the expected output. Surprisingly, what went wrong ? Let us analyze the above code & output we got.

    To keep it simple let us only consider the memory diagram of arr[0] an arr[1]. 

     

    Since the integer size is 4 bytes each array element has 4 bytes. The arr[0] will have bytes named as b0,b1,b3 and b3 storing the integer value of 10. Similarly arr[1] will have bytes named as b4,b5,b6 and b7 storing integer values of 20. 

     

    Note: The size of integer depends on the underlying CPU Architecture. Here we are assuming the machine to have 32 bit word size. 

     

    This memory diagram is depicted in the figure given below.

    Void Pointer in C
    Fig 7: Void Pointer in C Arithmetic with Arr[0] and Arr[1]

    When we make the vptr point to the array arr, it will hold the beginning address of arr[0] which is depicted in the figure given below:

    Void Pointer in C
    Fig 8: Void Pointer in C with Beginning Address

    When we are incrementing the void pointer variable vptr by executing the post increment operation vptr++, in the run time it will not know how many bytes to move the vptr as the type information is not defined. 

     

    Hence by default it will increment by one byte. So instead of moving the pointer address to the beginning of b4, it eventually ends up in the beginning address of b1.

    What is Void Pointer in C
    Fig 9 : Void Pointer in C with Incorrect Dereferencing

    Now when we try to dereference the pointer by executing the *(int*) vptr in the loop, it will read the next four bytes namely b1,b2,b3 and b4. Whereas our original idea was to deference b4,b5,b6 and b7. 

     

    Because of this incorrect dereferencing, we get an unexpected value of 335544320 instead of expected value of 20. 

     

    This is one of the side effects of the void pointer being a generic one. 

     

    Now the question is how to fix this problem? We need to increase the size of the pointer by explicitly adding the number of bytes rather than leaving it to the post increment operation. The updated code snippet is given below.

    What is Void Pointer in C
    Fig 10 : Correction to the Code given in Fig 5

    Here when we are explicitly incrementing the vptr by adding the current address with size which is nothing but the size of the integer. Here the proper pointer increment happens from b0 to b4. 

     

    Upon dereferencing the values from b4 to b7 are fetched from the memory the printed which is what is required. Here is the updated memory diagram with this changed code.

    Void Pointer in C
    Fig 11 : Void Pointer in C with Increment from B0 to B4

    Upon executing the code we get the correct output as follows.

    Output :

    Void Pointer Example in C
    Fig 12 : Expected Output for the Code given in Fig 10

    In summary one needs to be careful while performing pointer arithmetic. Rather than leaving the pointer arithmetic to the assumption of post increment or decrement operations, it should be done explicitly.

    3. Reusability of Void Pointer in C

    Let us talk about the third use case of void pointers. 

     

    One main advantage of using the void pointers is that it can be re-usable. Because of this feature of the void pointers, space and time complexities can be reduced to some extent, resulting in reduced resource usage.

     

    Such simple but powerful features come in handy in Embedded System designing, where resource optimization plays a very important role. 

    Let us take an example. By using the same void pointer, different data types can be pointed at different times. 

     

    Let us consider a small simple code snippet, to show how void pointers can be re-usable by making it point to integer, character, float and double. Instead of using different pointer variables, we are using a single pointer variable called vptr, which will give a better space complexity in terms of memory usage.

    Void Pointer Example in C
    Fig 13 : Void Pointer Reusability

    Output :

    Fig 14 : Output of the Code Shown in Fig 13

    Conclusion

    In conclusion we can say void pointers in C programming serve as versatile tools with generic capabilities. They allow us to handle data of any type, making memory management and data manipulation more flexible and convenient.

     

    Void pointers facilitate reusability and reduce space complexity, which is particularly valuable in Embedded System designing. Though they lack a specific data type, proper typecasting enables referencing and dereferencing, making them indispensable for tasks involving different pointer types in the same code.

     

    However you need to be careful while dealing with void pointer arithmetic. If you are not making explicit handling, it may result in unexpected side-effects.

     

    Features like void pointers in C make C programming very much suitable for programming Embedded Systems as all the examples mentioned in this blog post come in handy while writing any Application for Embedded Systems.

    SN Related Blogs Links
    1. Enumeration in C Click Here
    2. Type Promotion in C Click Here
    3. Difference between typedef and macro in C Click Here

    People Also Ask(PAA)

    The main advantage of using void pointers is their ability to point to data of any data type.Void pointers allow for more flexible memory management and data manipulation, making them particularly valuable in situations where data types may vary or need to be handled dynamically.

    No, you can’t directly use arithmetic operations like addition or subtraction on void pointers. Void pointers lack data type information needed for proper memory calculations. To use arithmetic, cast the void pointer to a specific type like  “ int* ”, perform the operation, then cast it back if needed for void pointer behavior.

    Typecasting a void pointer during dereferencing is essential because void pointers lack specific data type information. Without typecasting, the compiler wouldn’t know how many bytes to read from memory. Typecasting provides the needed data type context for proper interpretation and memory access.

    Share this material with your friend: