C++ Void Pointer - C++ Programming Tutorial
C++ Course / Pointers & References / C++ Void Pointer

C++ Void Pointer

BLUF: Mastering C++ Void Pointer is a critical step in becoming a proficient C++ developer. This lesson provides a deep dive into the syntax, performance considerations, and real-world applications of this concept.
Key Performance Insight: C++ Void Pointer

C++ is renowned for its efficiency. Learn how C++ Void Pointer enables low-level control and high-performance computing in the tutorial below.

In C++, a void pointer is a distinct pointer type capable of holding the memory address of any data type. It serves as a versatile pointer since it is not tied to any particular data type. The compiler interprets it as a raw memory address due to its absence of type specificity.

In C++, a void pointer is declared using the void* keyword. Nevertheless, before retrieving the value in C++ tutorials, a void pointer must be explicitly cast to the appropriate data type. This approach enhances the flexibility of void pointers but requires careful handling to prevent type-related issues in C++.

Syntax

It has the following syntax:

Example

void* ptr_name;

In this particular format,

  • ptr_name signifies the identifier for the pointer's name.
  • C++ Void Pointer Example

Let's consider an example to demonstrate the concept of the null pointer in C++.

Example

Example

#include <iostream>

using namespace std;   //using standard namespace

void printValue(void* ptr, char type) {

    // Use type indicator to cast and print the value

    switch(type) {

        case 'i': // int

            cout << "Integer value: " << *(int*)ptr << endl;

            break;

        case 'f': // float

            cout << "Float value: " << *(float*)ptr << endl;

            break;

        case 'c': // char

            cout << "Character value: " << *(char*)ptr << endl;

            break;

        default:

            cout << "Unknown type!" << endl;

    }

}

int main() {    //main function

    int a = 42;

    float b = 3.14;

    char c = 'A';

    void* ptr;

    // Point to an int

    ptr = &a;

    printValue(ptr, 'i');

    // Point to a float

    ptr = &b;

    printValue(ptr, 'f');

    // Point to a char

    ptr = &c;

    printValue(ptr, 'c');

    return 0;

}

Output:

Output

Integer value: 42

Float value: 3.14

Character value: A

Explanation:

In this illustration, we showcase the utilization of a void (generic pointer) to reference various data types like integers, floating-point numbers, and characters. Subsequently, we introduce a printValue function that receives a void pointer along with a type indicator ('i', 'f', 'c') to accurately convert and display the referenced value.

Key Features of Void Pointer

Several void pointers in C++ are as follows:

  • General Nature: An address of any data type can be stored in a void pointer.
  • Required Type Casting: We must cast a void pointer to the suitable data type before dereferencing it because it lacks an associated type.
  • No Use of Pointer Arithmetic: The compiler cannot execute arithmetic operations because it is unable to determine the size of the data type being pointed on.
  • Type safety is not enforced: Since the pointer has no type, incorrect type casting may cause runtime problems or undefinable behavior.
  • Commonly used in C and C++: C++ employs it when creating flexible, low-level code or interfacing with C code, even though it's more common in C.
  • Different ways of utilization of void pointer in C++

There are various methods of utilizing a void pointer in C++. Some of these include:

Generic Functions

In C++, utilizing void pointers allows for the development of versatile functions that can operate on any data type. This capability proves beneficial when functions such as swap, compare, or copy require the flexibility to work across various types of data without the need for redundant code.

C++ Void Pointer Example using Generic Functions

Let's consider an example to demonstrate the concept of a void pointer when utilizing generic functions in C++.

Example

Example

#include <iostream>

#include <cstring>    //using for strcmp

using namespace std;  //using standard namespace

int compare(void* a, void* b, char type) {

    switch(type) {

        case 'i':

            return (*(int*)a - *(int*)b);

        case 'f':

            return (*(float*)a > *(float*)b) ? 1 : (*(float*)a < *(float*)b ? -1 : 0);

        case 's':

            return strcmp((char*)a, (char*)b);

        default:

            return 0;

    }

}

int main() {   //main function

    int x = 35, y = 20;

    float p = 3.58, q = 2.78;

    char s1[] = "apple", s2[] = "banana";

    cout << "Compare ints: " << compare(&x, &y, 'i') << endl;   //compare integers

    cout << "Compare floats: " << compare(&p, &q, 'f') << endl;   //compare floats

    cout << "Compare strings: " << compare(s1, s2, 's') << endl;   //compare strings

    return 0;

}

Output:

Output

Compare ints: 15

Compare floats: 1

Compare strings: -1

Explanation:

In this instance, a void* pointer and a type indicator are employed to compare values of varying data types. Subsequently, a compare function is utilized to convert the generic pointers according to the specified type and execute suitable comparisons.

Dynamic Memory Allocation with Void Pointers

In C++, when memory is dynamically allocated using the calloc or malloc function, a void* is the type of pointer that gets returned. It is necessary to typecast the void pointer before utilizing it. Void pointers prove to be beneficial for handling memory when the type is unknown during allocation.

C++ Dynamic Memory Allocation with Void Pointers

Let's consider an example to demonstrate dynamic memory allocation using void pointers in C++.

Example

Example

#include <iostream>

#include <cstdlib> // for malloc and free

using namespace std;  //using standard namespace

int main() {   //main function

        void* ptr = malloc(5 * sizeof(int));

    if (ptr == nullptr) {

        cout << "Memory allocation failed!" << endl;

        return 1;

    }

    // Typecast to incpp tutorialer

    int* intPtr = (int*)ptr;

    // Initialize and print

    for (int i = 0; i < 5; ++i) {

        intPtr[i] = (i + 1) * 10;

        cout << "Value at index " << i << ": " << intPtr[i] << endl;

    }

    // Free memory

    free(ptr);

    return 0;

}

Output:

Output

Value at index 0: 10

Value at index 1: 20

Value at index 2: 30

Value at index 3: 40

Value at index 4: 50

Explanation:

In this instance, memory allocation for 5 integers is dynamically performed utilizing malloc along with a void pointer. Subsequently, the pointer is cast as an int to handle integer values. The array is then initialized with multiples of 10, followed by printing each individual value.

Callback Functions with Void Pointers

In C++, the void pointer is frequently utilized in low-level programming and systems to facilitate the passing of user-defined data in callback functions. The adaptability and generic nature of callbacks are maintained by transmitting any contextual data via the void.

C++ Callback Function with Void Pointers

Let's examine an example to demonstrate the callback function using void pointers in C++.

Example

Example

#include <iostream>

using namespace std;   //using standard namespace

// Callback function type

typedef void (*Callback)(void*);

void executeCallback(Callback cb, void* data) {

    cb(data);

}

void printMessage(void* msg) {  //using a simple callback function

    cout << "Message: " << (char*)msg << endl;

}

int main() {   //main function

    char message[] = "Hello from callback!";

    executeCallback(printMessage, message);

    return 0;

}

Output:

Output

Message: Hello from callback!

Explanation:

In this illustration, we showcase the utilization of a function pointer (callback) along with a void pointer to transmit generic data. Subsequently, we have created an executeCallback function that leverages a callback and a void data pointer, enabling versatility in the data type transmitted. Within the main function, a message gets transmitted to the callback function printMessage, which performs a typecast of the void to char and displays the message.

Conversion of Void Pointer to Constant

In C++, using const with void pointers indicates that the referenced data is immutable. With a const void* pointer, the data remains constant, allowing redirection without modification. This approach is valuable for securely passing read-only data to functions, particularly when dealing with generic pointers or APIs to safeguard the original data.

Converting a void pointer to a constant in C++ Example:

Example

void* ```
void* ptr_name;

const int constPointer = static_cast<const int>(```

void* ptr_name;

Example

Let's consider a scenario to demonstrate the transformation of a void pointer into a constant in C++.

Example

Example

#include <iostream>

using namespace std;  //using standard namespace

void printValue(const void* ptr, char type) {

    switch (type) {

        case 'i':

            cout << "Integer Value is: " << *(const int*)ptr << endl;

            break;

        case 'f':

            cout << "Float Value is: " << *(const float*)ptr << endl;

            break;

        case 'c':

            cout << "Character Value is: " << *(const char*)ptr << endl;

            break;

        default:

            cout << "Unknown type!" << endl;

    }

}

int main() {   //main function

    int a = 57;

    float b = 5.79f;

    char c = 'T';

    // Declare const void pointers

    const void* ptr1 = &a;

    const void* ptr2 = &b;

    const void* ptr3 = &c;

    printValue(ptr1, 'i');

    printValue(ptr2, 'f');

    printValue(ptr3, 'c');

    return 0;

}

Output:

Output

Integer Value is: 57

Float Value is: 5.79

Character Value is: T

Explanation:

In this instance, we showcase the application of const void pointers for accessing data of different types without altering it. Subsequently, a printValue function is implemented. This function accepts a const void pointer and a type indicator, then converts the pointer to the relevant type according to the indicator before displaying the value.

C++ Another Example to Generic swap using Pointers

Let's consider a different instance to showcase the general exchange using pointers in C++.

Example

Example

#include <iostream>

#include <cstring> // for memcpy

using namespace std;  //using standard namespace

// Generic swap function using void pointers

void genericSwap(void* a, void* b, size_t size) {

    // using a temporary buffer

    void* temp = malloc(size);

    // Copy a into temp

    memcpy(temp, a, size);

    // Copy b into a

    memcpy(a, b, size);

    // Copy temp into b

    memcpy(b, temp, size);

    // Free the temporary buffer

    free(temp);

}

int main() {  //main function

    int x = 10, y = 20;

    float m = 1.5f, n = 2.5f;

    cout << "prior swapping integers: x = " << x << ", y = " << y << endl;

    genericSwap(&x, &y, sizeof(int));

    cout << "upon swapping integers:  x = " << x << ", y = " << y << endl;

    cout << "\nprior swapping floats: m = " << m << ", n = " << n << endl;

    genericSwap(&m, &n, sizeof(float));

    cout << "upon swapping floats:  m = " << m << ", n = " << n << endl;

    return 0;

}

Output:

Output

Prior swapping integers: x = 10, y = 20

Upon swapping integers:  x = 20, y = 10

Prior swapping floats: m = 1.5, n = 2.5

Upon swapping floats:  m = 2.5, n = 1.5

Explanation:

In this instance, any data type can be employed as an address by utilizing void* within the genericSwap function. Following that, the values are transferred between the variables utilizing a temporary buffer and the memcpy function.

Advantages of Void Pointer

Several advantages of Void pointer in C++ are as follows.

  • The void pointer helps us to point to any data type, which makes the code more flexible and reusable.
  • We can write our data structures and generic functions to work with different data types.
  • It can be helpful for dynamic memory management in situations when types are unknown until runtime.
  • These pointers are mainly beneficial when interfacing with legacy C code or system-level C libraries, particularly in embedded or low-level programming environments.
  • Disadvantages of Void Pointer

Several disadvantages of Void pointer in C++ are as follows.

  • The compiler is unsure about the type to which the pointer belongs, which raises the risk of issues brought on by incorrect type casting.
  • It can cause issues to explicitly cast a void pointer to the correct type before accessing the contents.
  • It can be challenging to understand and maintain code that heavily relies on void pointers, particularly in large projects.
  • Undefined behavior or crashes may occur when a void reference that has been cast wrongly is dereferenced.
  • Conclusion

In summary, void pointers in C++ are unique pointers capable of storing addresses of any data type. They provide versatility and are frequently employed in tasks such as memory handling, generic programming, and callback functions. Unlike other pointers, void pointers lack type safety, requiring explicit type casting which, if done incorrectly, can introduce errors and potentially cause undefined behavior.

C++ Void Pointer FAQs

1) What exactly is a void pointer in C++?

In C++, a void pointer (void*) can refer to any data type. This feature is beneficial for generic programming or handling unfamiliar data types as it serves as a versatile pointer without a specific type attached to it.

2) Can a void pointer be dereferenced directly?

In C++, a pointer without a defined type cannot be explicitly dereferenced. Consequently, direct dereferencing is impossible as the compiler does not possess the essential information about the pointer's data type. Prior to dereferencing, it is imperative to cast it to the appropriate type.

Example

int a = 5;

void* ptr = &a;

cout << *(int*)ptr; // Correct

3) What are the advantages of a void pointer over a regular pointer?

A void pointer is primarily employed in generic functions or data structures that need to operate with various data types, particularly when the data type is unspecified at compile time.

4) What are the void pointer's limitations?

Several limitations of void pointers in C++ are as follows:

  • It is impossible to dereference without typecasting.
  • Pointer maths is not authorized.
  • Lack of type safety can cause runtime errors.
  • More challenging to maintain and debug than type-safe replacements.
  • 5) What are better alternatives to void pointers in C++?

Modern C++ allows us to use the void pointers in several scenarios. Some of them are as follows:

  • Templates for generic functions and classes.
  • If we want to store any type safely, we can use the std::variant or std::any from the headers.
  • These solutions offer similar flexibility but with improved type-checking and maintainability.

Input Required

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

Logic Practice
Install Logic Practice
Add to home screen for a faster app-like experience