Search

6.13 — Void pointers

The void pointer, also known as the generic pointer, is a special type of pointer that can be pointed at objects of any data type! A void pointer is declared like a normal pointer, using the void keyword as the pointer’s type:

A void pointer can point to objects of any data type:

However, because the void pointer does not know what type of object it is pointing to, it cannot be dereferenced directly! Rather, the void pointer must first be explicitly cast to another pointer type before it is dereferenced.

This prints:

5

The next obvious questions is: If a void pointer doesn’t know what it’s pointing to, how do we know what to cast it to? Ultimately, that is up to you to keep track of.

Here’s an example of a void pointer in use:

This program prints:

5
7.5
Mollie

Void pointer miscellany

Void pointers can be set to a null value:

Although some compilers allow deleting a void pointer that points to dynamically allocated memory, doing so should be avoided, as it can result in undefined behavior.

It is not possible to do pointer arithmetic on a void pointer. This is because pointer arithmetic requires the pointer to know what size object it is pointing to, so it can increment or decrement the pointer appropriately.

Note that there is no such thing as a void reference. This is because a void reference would be of type void &, and would not know what type of value it referenced.

Conclusion

In general, it is a good idea to avoid using void pointers unless absolutely necessary, as they effectively allow you to avoid type checking. This allows you to inadvertently do things that make no sense, and the compiler won’t complain about it. For example, the following would be valid:

But who knows what the result would actually be!

Although the above function seems like a neat way to make a single function handle multiple data types, C++ actually offers a much better way to do the same thing (via function overloading) that retains type checking to help prevent misuse. Many other places where void pointers would once be used to handle multiple data types are now better done using templates, which also offer strong type checking.

However, very occasionally, you may still find a reasonable use for the void pointer. Just make sure there isn’t a better (safer) way to do the same thing using other language mechanisms first!

Quiz

1) What’s the difference between a void pointer and a null pointer?

Quiz answers

1) Show Solution

6.14 -- Pointers to pointers
Index
6.12a -- For-each loops

62 comments to 6.13 — Void pointers

  • The Perplexed Programmer

    Hello Alex!
    Fantastic tutorials, just a small typo

    rather than

        
    It’s the program with void pointer in use.
    Thanks for the tutorials!

  • zjwelch

    Great explanation, but I’m a bit fuzzy on using this properly in my situation. For clarifications sake, let’s say I had a class dooDad that returned an object of itself( dooDad newDooDad = dooDad(init1,init2);), and then I had say two or three classes like dooDad (A, B, C for instance) class that were different and wanted to create a new class that could be any of the three and static cast to that chosen dooDad type like this?

    class AmazingDooDad {

      private:
      
        void *anyDooDad;

      public:

       bool AmazingDooDad( varchar(1) objType );
       some other variables;

    };

    bool AmazingDooDad::AmazingDooDad( varchar(1) objType ) {

      switch( objType ) {

        case ‘A’:
           //cast to dooDad type ‘A’
           *anyDooDad = &static_cast<dooDad(init1,init2)*>(anyDooDad);
           return true;
        case ‘B’:
           …

        default : return false;
      }
    }

    what I *THINK* is happening here would be that the void pointer is receiving the address from the staticly cast newly created object of class type dooDad (which is created with init1 and init2). This is essentially what I’m trying to do, so if it’s not right please do explain where my thinking is wrong.

    • Alex

      This program won’t compile, and the logic doesn’t really make sense. static_casting a void pointer allows you to change the type, but the underlying address stays the same. static_casting a void* to another type and then reassigning back to a void* is essentially a no-op.

      Given what you’re trying to do here, I’d probably recommend using inheritance for this instead of void pointers. AmazingDooDad could be a pure interface base class, and each of the individual DooDads could be derived from it. Then you’d have a virtual function allowing you to self-identify which DooDad a given AmazingDooDad is.

      If you want to use void pointers, then I’d recommend the following:
      * AmazingDooDad should maintain the type information for anyDooDad.
      * It should be up to the user of the class to do the static_cast themselves.

      • zjwelch

        I understand your point, but it makes my plan more confusing than before. What I’m specifically trying to accomplish is allow the definition of a private object that all functions in the class have in their scope, but won’t know which of two (or more) classes that object will be until creation. Ie. created with ‘A’ flag or ‘B’ flag, and then use that same variable name through the class to refer to whichever object was created (because they behave the same, but have different properties).

        There are two classes for heat/hum sensors that I’m using. DHT.h and HTU21DF.h
        Once created they have different read mechanisms, but work very similiarl. I’m trying to create a wrapper class called heatHum.h/cpp so I can create a new object of either by using the constructor to define internally to the class which sensor is in use.

        Truncated code:

        /*-- heatHum.h --*/

        #include "DHT.h"
        #include "HTU21DF.h"

        class heatHum {

        private:

           void *sensor;

        public:

           bool heatHum( varchar(3) );
           float getTemp();

        };

        /*-- heatHum.cpp --*/

        bool heatHum::heatHum( varchar(3) type ) {

          switch( type ){
            case ‘DHT’:
               sensor = ?; //create dht object with DHT newSensor( inputPin, initID );
               return true;

            case ‘HTU’:
               sensor = ?; //create htu object with HTU21DF newSensor = HTU21DF();
               return true;

            default:
               return false;
          }
        }

        float getTemp(){

           if( *sensor = ? ){ //DHT
              //read sensor DHT
           } else if( *sensor = ? ) { //HTU
              //read sensor HTU
           }
        }

        /*-- Arduino Sketchfile --*/

        #include heatHum.h

        void setup(){
          
          if( heatHum sensorHH( ‘HTU’ ) ) {
             Serial.println("success");
          } else {
             Serial.println("failure");
          }

        }

        void loop(){

           float currTemp = sensorHH.getTemp();
           //do stuff

        }

        //EOF

        The reason for this is some of the intended uses for this system will have one or the other sensor, and some will have both. I could just create a private flag variable and set it in the constructor and reference it for each function, but then each instance of the class would waste the memory of both sensors every time. My pragmatic side feels like that is inefficient and therefore should be avoided, but only if there is a feasible way to do it more elegantly.

        Thoughts?

        • Alex

          I still think you should use inheritance for this.

          heatHum is your base class, and contains the public interface, consisting of virtual functions for any function you want exposed to users of the class. DHT and HTU21DF are your derived classes, each having different implementations of the functions in the base class.

          At runtime, you can create a DHT or a HTU21DF as needed. You can use the heatHum interface to access that class according to the public interface. This is much cleaner than trying to use void pointers for this stuff.

  • Rohit

    Why u used * before static_cast in case of int and float in the function? Does it mean anything?

    #include <iostream>

    enum Type
    {
        INT,
        FLOAT,
        CSTRING
    };

    void printValue(void *ptr, Type type)
    {
        switch (type)
        {
            case INT:
                std::cout << *static_cast<int*>(ptr) << ‘\n’; // cast to int pointer and dereference
                break;
            case FLOAT:
                std::cout << *static_cast<float*>(ptr) << ‘\n’; // cast to float pointer and dereference
                break;
            case CSTRING:
                std::cout << static_cast<char*>(ptr) << ‘\n’; // cast to char pointer and dereference
                break;
        }
    }

    int main()
    {
        int nValue = 5;
        float fValue = 7.5;
        char szValue[] = "Mollie";

        printValue(&nValue, INT);
        printValue(&fValue, FLOAT);
        printValue(szValue, CSTRING);

        return 0;
    }

    • Alex

      The * means dereference, which in English means, “get the value the pointer is pointing to”. Without this, we’d be casting the _address_ the pointer is holding to an integer or float, which isn’t what we want. We want to cast the _value_ that the pointer is pointing to to an integer or float, and that requires dereferencing the pointer.

      • Rohit

        Hats off man. Great explanation. You cleared all my confusion now. Thank you.

      • Gerald

        I’d like to ask some clarification on this. I understand deference, but why does the char array not need to be dereferenced?

        • Alex

          Char arrays (and pointers of type char*) have special handling where std::cout knows to treat that type as a C-style string. std::cout will walk through the array until it hits a null terminator.

  • raja ratnam

    array of void pointer can be created in c++

  • Hugh Mungus

    Dear Alex,

    Can we use the auto keyword in place of void so that we can know the type of the pointer and do pointer arithmetic and stuff?

    • Alex

      No. The auto keyword invokes type deduction, so you can use it to deduce the type the pointer should have, but that only happens at the point of definition. Once the pointer’s type has been determined, it can’t be changed.

      With auto, the following wouldn’t work:

      If you initialized ptr with nValue, ptr would become an int pointer. Then the compiler would complain when you tried to assign the address of another type (such as &fValue) to an int pointer.

  • Alejandro

    Good afternoon, im practising for an upcoming exam in C++ where we have to use void* Lists, the thing is that i cant figure out the way this kind of lists work in c++, and im struggling trying to figure out how to read a node, code below (will post also the abstract datatype because i had some issues with it along the practice:

    Main.cpp

    Lista.h (only where the adt should be assigned)

    Foto.h

  • Hey Alex,
    Why is the asterisk(*) used only for ‘case INT’ and ‘case FLOAT’ ,but not for ‘case CSTRING’ ?
    Eagerly waiting for your response.
    Regards.
    Prajwal.

  • Jatin

    Hey Alex,can a void pointer point to a variable of enum type.

  • Elpidius

    Hey Alex,

    I just noticed a typo in your 3rd example of code. The CSTRING shouldn’t have a comma after it, for maximum compatibility.

    i.e.

    I remember this from lesson 4.5 Enumerated types. 🙂

  • Rob G.

    Hi Alex your site is awesome. Have a question here very basic.

    Regarding

    In this case the voidPtr IS pointing to &value. Its not exactly 100% a null pointer right b/c it points to real memory (&value)? Is this strictly a syntax issue addressed at compilation with static cast? Plz help clear up the confusion.

    • Rob G.

      Meant void pointer, and it can point to any type. It just can’t dereference until static_cast to the same type occurs. So it has no type yet points toward int.

      Sorry Alex, I should have read more carefully. : )

    • Alex

      voidPtr is a void pointer (meaning it has type void), not a null pointer (meaning it’s not pointing to anything).

      If you set voidPtr to 0 (or nullptr), then it would be both a void pointer and a null pointer. They aren’t mutually exclusive.

  • Venkata Prasad

    Hi Alex,

    I dont have any question,but want to convey my deepest thanks to you.
    Hailing from non computers background learning c++ seemed a big ordeal.
    Even after trying to read huge books with 1500+ pages I could never develop any concepts,best I could do was remember few things here and there.

    When I discovered learncpp.com I instanly figured that this is what I was looking for,touching almost every topic in c++,conveying to the point precisely emphasising with code and believe c++ never seemed so  easy.I am almost half way through your site (in 8th chapter) but feels very confident that I have learned many things.Best thing I discovered just now  in this portal is you replying to the questions posed in the threads below every chapter.Awesome work 🙂  Thanks alot.Again Thank you so much

    Sorry if I wasted your time writing so much prose(not even 1 line of c++ ) sorry 🙂

    Yeah I dont have any questions so far

    Thanks
    Venkata Prasad

  • Mr D

    Another question: i notice some people on this site have avatar pictures…….not that i particularly need or want that, but it makes me think there’s some way to register and log in to this site, though i don’t see the option anywhere on the site!

  • Mr D

    In the part of this chapter explaining dereferencing a void pointer, you gave the code:

    But wouldn’t it be clearer to skip the intermediate step of creating

    and in fact could just do:

    Because in the later example in the tutorial you do just that:

    So i was scratching my head for a while about that!

  • Nope, I didn’t find any code like this: char *szValue = "Mollie";
    So, it’s not covered in lesson 6.6. A similar syntax is const char *szValue that is covered in lesson 6.8b — C-style string symbolic constants 🙂

  • cpplx

    char *szValue = "Mollie";
    confussing line
    declaring a char type pointer pointing to a string?!
    im quite unexperienced to understand it.

    all i have seen so far in the lessons is
    declaring an object(?);
    declaring a pointer to that object;

  • Connor

    Hello again Alex.

    Maybe I haven’t progressed far enough yet (and maybe they exist in later lessons) but do you have any exercises in regards to pointers, references, and arrays in order for us to confirm our understanding of the material?

    Thanks again

  • Sir

    What is the meaning of (void *)0?
    null pointer
    void pointer
    error

  • Steven

    "Note that since void pointers can’t be dereferenced, there is no such thing as a void reference."
    Can u explain it more detail? To be honest, I have not thought about why there is no a void reference. I consider it’s just a kind of rule. Thanks a lot!

  • Alex

    "Similarly, it is not possible to do pointer arithmetic on a void pointer"

    This is plain wrong! Of course you can do arithmetic on void pointers.

    • Steven

      Really? How can u do it? Show me code please.

    • Alex

      Pointer arithmetic works by incrementing or decrementing the memory address by the size of the object pointed to. Since void pointers don’t know what they’re pointing to, this doesn’t work.

      Consider:

  • pjhc

    why when you use:

    cout << static_cast(pValue) << endl; // without the (*) symbol, you get the whole word "molly", unlike the case you do the same but with an int type pointer, and get the direction that it is point to?

    char *szValue = "Mollie"; // here you used pointer

    or

    char szValue[] = "Mollie";
    cout<<szValue1<<endl; // it gives "mollie"

    int numbers[5]={'1','2','3','4','5' };
    cout<<numbers; // it gives 0x28fefc

  • Matti

    It would be very helpful to have some practice (e.g. programs to write) with pointers and dynamic memory allocation here!

    But thanks for a wonderful site Alex! Really fun.

  • dim

    Congratulations for your site. It is really helpful.

  • AstroBoy

    Alex,
    I’m a new user to your site. IT IS AWESOME!! I will be visiting it often. Thanks for all your hard work.

    AB

  • sachin_kunal

    is dangling pointer and void pointer same

    • Alex

      No. A dangling pointer is a pointer that points to memory that has been deallocated. A void pointer is a pointer that can point to any type of data.

  • Henry

    I use a wide variety of materials to learn from, but this site alway cleans up the problems or questions. ty 🙂

  • Tom

    So you can’t do this? =[

    Thank you very much for your tutorials!

  • Noha

    is there any reason for using pointer(*) for char but reference (&) for float and int?

    • I used a pointer in the char declaration because it’s an array of chars, not just a normal char. You can also declare it like this:

      The Print() function takes a pointer as it’s first argument. In this context, the & is used to pass the address of a normal variable to a pointer parameter.

      • Danny

        This would be difficult to understand for people learning from this tutorial, since you are pointing to a literal, which you haven’t explained.

        I.e, why would a literal have an address you can point to? I’ve seen people type char * szString before, and I was hoping to understand that.

      • Hagen

        I’m struggling a bit with pointers, could someone confirm if I have understood this correctly?

        the first parameter the Print function takes is a pointer. When printing nValue and fValue, the pointer pValue is set to their addresses. However szValue has already been declared as a pointer, therefore it is passed directly into the function (?)

        • Alex

          Yup. Since szValue is already a pointer, we can just pass it in, and it will get implicitly converted to a void pointer. Since the other two aren’t pointers, we need to pass in their addresses.

  • sergk

    Void pointers used in custom memory allocators as well - malloc, CoTaskMemAlloc, etc.. Memory allocation routines usually don’t aware of data types they allocating memory for.

    -serg

    • V

      Note that C++ offers “new” as a type-safe way to allocate memory instead of the C malloc(). Also note that C++ offers many containers and constructs that eliminate the need for explicit new anyways, e.g.:

      Instead of:

      V

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter