Bob Johnson
Bob Johnson

Reputation: 95

How do you use the void pointer in C?

Here are a couple of function declarations that I'm having trouble understanding how to complete. I've scanned the web to see what a void pointer is, and I understand that it must be cast to something to be useful (because it just points to some memory block), but I don't see how that helps in completing these declarations.

/* type of comparison function that specifies a unique order.
   Returns 1 if pointer1 should come before,
   0 if equal to, or -1 if after pointer2. */
typedef int (*compare_function) (const void* pointer1, const void* pointer2);

/* get the data object */
void* get_obj(const void* item_pointer);

There are more functions like this, but I think if I understand how to do these two I should be in good shape. For example, for the second function, how do we cast the item_pointer to anything appropriate that should be returned?

Upvotes: 3

Views: 278

Answers (3)

Niklas Rosencrantz
Niklas Rosencrantz

Reputation: 26652

Sorting in C with quicksort uses void pointers so that we can sort any data in arrays. The sort function must return -1, +1, or 0 if the parameter b is before, after or the same as parameter a

#include <stdio.h>
#include <stdlib.h>

int sort_order( const void *, const void *);

int main(void)
{
  int i;
  char alfa[6] = { ’C’, ’E’, ’A’, ’D’, ’F’, ’B’ }; 
  qsort( (char*)alfa, 6, sizeof(char), sort_order); 
  for (i=0 ; i<5 ; i++)  // now in order?
     printf("\nchar %d = %c",i, alfa[i]);
  printf("\n");
  system("PAUSE");
  return 0;
}

int sort_order( const void* a, const void* b)
{
  if      ( *((char*)a) < *((char*)b) )     return -1 ;
  else if ( *((char*)a) > *((char*)b) )     return  1 ;
  else                                      return  0 ;
}

Then you can sort your own datatypes:

typedef struct {   float left;   float right;} ears;
typedef struct{  char name[13];  int weight;  ears eararea;} monkey;    

monkey* Index[4];

for(i=0;i<4;i++)   
    Index[i]= (monkey* )malloc(sizeof(monkey));     

qsort((void* ) Index, 4, sizeof(monkey* ), sort_order);

// Sorted by weight    
int sort_order( const void* a, const void* b) {   
    if((**((monkey** )a)).weight < (**((monkey** )b)).weight) return -1 ;   
    else if ((**((monkey** )a)).weight > (**((monkey** )b)).weight ) return  1 ;
    else return  0 ;
}

Complete program

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    float left;
    float right;
} ears;

typedef struct {
    char name[13];
    int weight;
    ears eararea;
} monkey;

int sort_monkeys( const void *, const void *);

int main(void)
{   monkey* monkeys[4];
    int i;
    for(i=0; i<4; i++) {
        monkeys[i]= (monkey* )malloc(sizeof(monkey));
        monkeys[i]->weight=i*10;
        if (i==2)
            monkeys[i]->weight=1;
    }
    for (i=0 ; i<4; i++)
        printf("\nchar %d = %i",i, monkeys[i]->weight);

    qsort((void* ) monkeys, 4, sizeof(monkey* ), sort_monkeys);

    for (i=0 ; i<4; i++)  // now in order?
        printf("\nmonkey %d = %i",i, monkeys[i]->weight);
    return 0;
}

// Sorted by weight
int sort_monkeys( const void* a, const void* b) {
    if((**((monkey** )a)).weight < (**((monkey** )b)).weight) return -1 ;
    else if ((**((monkey** )a)).weight > (**((monkey** )b)).weight ) return  1 ;
    else return  0 ;
}

Upvotes: 1

Clifford
Clifford

Reputation: 93466

Any pointer type may be assigned to a void*, this is useful in cases where a function does not need to know the type, or the type information is conveyed by other means. This allows you to write just one function to deal with any pointer type rather than a separate function for each data type.

While you cannot dereference a void* you can cast it to any type and dereference it - the semantics of that - i.e. whether it is meaningful, depends on the code and is not enforced byte compiler.

Frequently a generic function is not interested in the content of some block of data, just its address and often its size.

As a simple example:

void memcopy( void* to, void* from, int length )
{
    char* source = (char*)from ;
    char* dest = (char*)to ;
    int i ;

    for( i = 0; i < lengt; i++ )
    {
        dest[i] = source[i] ;
    }
}

int main()
{
    typedef struct
    {
        int x ;
        int y ;

    } tItem

    tItem AllItems[256] = {0} ;
    tItem AllItemsCopy[256] ;

    memcopy( AllItemsCopy, AllItems, sizeof(AllItems) ) ;
}

See that memcopy() does not need to know what a tItem is in order to copy an array of them, it only needs to know the addresses and the size on the array in bytes. It casts the void* pointer arguments to reinterpret the data as a char array to perform a byte-by-byte copy. To do that it does not need to know the internal semantics of tItem or any other data object passed to it.

Upvotes: 0

user1129665
user1129665

Reputation:

void * usually means that you are only interested in the address of the data regardless of its type, some of the reasons:

  • the internal representation of the data this void * pointing to is hidden, you are not supposed to access the data directly, information hiding, your function 2 is properly an example of this case.

  • the type is known by some function in the call chain, like with qsort and most functions that pass arguments to other functions.

  • the type is not required because the data the pointer is pointing to will be handled as different type, like with memcpy which may handle the data as bytes, unsigned char *.

Upvotes: 9

Related Questions