Rontogiannis Aristofanis
Rontogiannis Aristofanis

Reputation: 9063

How to use void*

I am imlementing a simple merge function and I have got stuck, as the compiler gives me errors that I cannot explain. Here is my merge function:

void merge(void *a, int beg, int middle, int end, int (*cmp)(const void*, const void*
{
  std::stack<void*> first;
  std::stack<void*> second;

  for(int i = beg; i < middle; i++) {
   first.push(a+i);
  }
  for(int i = middle; i < end; i++) {
    second.push(a+i);
  }

  for(int i = beg; i < end; i++) {
    if(first.empty()) {
      void *tmp = second.top();
      second.pop();
      a+i = tmp;
    } else if(second.empty()) {
      void *tmp = first.top();
      first.pop();
      a+i = tmp;
    } else if(cmp(first.top(), second.top())) {
      void *tmp = first.top();
      first.pop();
      a+i = tmp;
    } else {
      void *tmp = second.top();
      second.pop();
      a+i = tmp;
    }
  }
}

And here is the error:

sort.h: In function `void merge(void*, int, int, int, int (*)(const void*, const void*))':
sort.h:9: error: pointer of type `void *' used in arithmetic
sort.h:12: error: pointer of type `void *' used in arithmetic
sort.h:19: error: pointer of type `void *' used in arithmetic
sort.h:19: error: non-lvalue in assignment
sort.h:23: error: pointer of type `void *' used in arithmetic
sort.h:23: error: non-lvalue in assignment
sort.h:27: error: pointer of type `void *' used in arithmetic
sort.h:27: error: non-lvalue in assignment
sort.h:31: error: pointer of type `void *' used in arithmetic
sort.h:31: error: non-lvalue in assignment

Can anyone help me? TIA.

Upvotes: 1

Views: 4955

Answers (5)

klement
klement

Reputation: 184

Function prototype probably should look something like this:

void merge(void **a, int beg, int middle, int end, int (*cmp)(const void*, const void*));

Then you can access every array member by its index without any problem.

Note: The size of object pointed by void is unknown as previously mentioned by Ferdinand (therefore a + i can't be applied), but the size of void* is known therefore updating prototype in a such way does the trick.

Upvotes: 1

Bo Persson
Bo Persson

Reputation: 92211

The problem with void* is that it is an address without a type. When you ask for a+i you say "move i elements further" without specifying what kind of elements. Is it one byte, one int, one car, one house, or one continent?

In C++ you don't have to use this kind of stuff, you can use templates and let the compiler figure out how to handle different types.

template<class T>
void merge(T* a, etc.

Upvotes: 1

Linuxios
Linuxios

Reputation: 35783

I can tell you about one of your errors. You're trying to do pointer arithmetic on a void*. You see, when you add to a pointer, you are adding however many bytes there are in the type of the pointer. So, if you add to a void*, the compiler can't know how many bytes to add, as void* has no type. Therefore, if you want to do it at the byte level, cast to a char*, or any other pointer level you want. If you want to do things byte by byte, you can take a void*, but cast to char*.

Upvotes: 0

Ferdinand Beyer
Ferdinand Beyer

Reputation: 67137

Pointer arithmetic is not possible with void*, since void has no size, and pointer arithmetic requires to compute memory addresses based on the size of the type.

If you expect beg, middle and end to represent byte offsets, you should use char pointers instead (one char is one byte).

If you want to write a generic function, that works with any type, don't use void pointers but templates:

template <typename t>
void merge(T *a, int beg, int middle, int end, int (*cmp)(const T*, const T*))
{
    // ...
}

Upvotes: 4

Balint
Balint

Reputation: 1415

In first.push(a+i);, you are trying to add an offset i to a void * pointer a. This is illegal.

You can add offsets to any other "something pointer", because that something will be defined and will have a defined size in memory. Therefore adding an offset of 1 will mean moving forward of sizeof(something) in memory. But void has no defined size. Therefore you cannot use offsets with void * pointers.

Upvotes: 1

Related Questions