Search code examples
cpointersvoid

How to handle array of void pointers


I would like to get a reference to an element at position in an array of void pointers. This is my function, I don't know if am doing it correctly. I have these two functions:

typedef struct vector 
{
  void **array;
  size_t size;
}vector;

I believe this gets the reference to the element at position pos.

void **get_at(vector *this, size_t pos) 
{
   assert(pos >=0 && pos < this->size);

   return &this->array[pos];
}

I believe this gets the pointer to the element at position pos.

void *at(vector *this, size_t pos) 
{
   assert(pos >=0 && pos < this->size);

   return this->array[pos];
}

I just would like to know if am correct with this implementation.

Just one more question: If I want to destroy the array, is doing it this way enough? Do I have to loop through the array elements freeing the memory held by each element?

void destroy(vector *this)
{
  free(this->array);
  free(this);
}

Solution

  • Do I have to loop through the array elements freeing the memory held by each element?

    This is something only you can know.

    There is a notion of ownership that is pervasive in all languages that support manual memory management. Every object is owned by some other object (or maybe by a group of objects but that's a bit more involved). When the owner dies, all objects owned by it die too.

    We tend to personify the objects a bit, so you will often hear questions like "who owns this?". This "who" refers to an object, not to a person.

    You have a vector of pointers that point to a bunch of objects. Who owns these objects? This is up to you to decide.

    If the vector itself is the owner, then it will be a good idea to free the objects when the array itself is freed. Note that freeing an object may be a bit more involved than just calling free() (just imagine that each of these objects is another vector). This is why a good vector would look something like this:

    typedef struct vector 
    {
      void **array;
      size_t size;
      void (*destroy)(void*); // call this for each object
                              // when freeing the vector
    } vector;
    

    You assign the destroy member when you initialise your vector.

    Your destroy function would look like this:

    void destroy(vector *this)
    {
      if (this->destroy) 
        for (int i = 0; i < this->size; ++i) 
          this->destroy(this->array[i]);
      free(this->array);
      free(this);
    }
    

    If your vector doesn't own objects it points to, it shouldn't try to destroy them. This vector implementation works in this case too, just assign a null pointer to this->destroy.

    You should design a coherent ownership structure for your program. There are no universal recipes.


    get_at and at look OK as is.