aurelienC
aurelienC

Reputation: 1183

Count elements of an unknown type array

Hello i am trying to write a function which return the number of elements of the array passed as parameter, the function have to work on an array of any type.

I tried this:

int nb_elems(void* array)
{
    void* end = array;
    while(*end != NULL) // The last element have to be null, it is not counted.
        end++;

    return end - array;
}

As you can guess, it doesn't work.

In fact it doesn't even compile, i get these errors:
Error: Illegal indirection. < while(*end != NULL) >
Error: void * : size unknown. < while(*end != NULL) >
Error: void * : size unknown. < return end - array >

First, could you tell me if what i am trying to do is possible?
Second, is the way i am trying to achieve this makes sense, or am i completely missing the point?
Then, why do i get these errors, what does they means?

Thanks for your help!

Upvotes: 1

Views: 1259

Answers (5)

Ian Abbott
Ian Abbott

Reputation: 17413

If you have an actual array, not a pointer, you can use sizeof(array) / sizeof(array[0]) to determine the number of elements in it.

Upvotes: -1

linluk
linluk

Reputation: 1670

because you are checking != NULL i suppose you have an array of pointers. with array of pointer your code could work because you know the size of pointers even if it is a void pointer.

if my assumptions were right you could code it like this:

int nb_elems(void** array) {
    void** end = array;
    while(*end != NULL) {
        end++;
    }
    return end - array;
}

but this code only works with pointer to pointer or array of pointer.


usage:

int** iptrs = (int**)malloc(3 * sizeof(int*));

iptrs[0] = (int*)malloc(sizeof(int));
*(iptrs[0]) = 42;
iptrs[1] = (int*)malloc(sizeof(int));
*(iptrs[1]) = 23;
iptrs[2] = NULL;

printf("%d", nb_elems(iptrs));

the example prints 2

Upvotes: 1

chux
chux

Reputation: 153660

As C does not pass arrays, nb_elems(void* array) received a pointer. The void *pointer does not know how many elements (nor the type) which its points to.

Since it needs to "work on an array of any type", code needs to define how to compare an arbitrary type with NULL.

To your function, you need to pass the pointer, the size of an array element and a function to use to test against NULL.

int nb_elems(void* array, size_t esize, int (*cmp)(void *ptr)) {
  char *ptr = array;
  int count = 0;
  while (*cmp(ptr) == 0) {
    ptr += esize;
    count++;
  }
  return count;
}

Upvotes: 3

Shadowwolf
Shadowwolf

Reputation: 983

The reason your code doesn't compile, is because of the fact that the compiler cannot determine the size of a void. Take for example the ++ operator. We could roughly translate this to:

end = end + sizeof(void);

The size of a void is not defined, so the compiler cannot generate any code for this, giving you one error.

Next you try to dereference a void pointer. This would give you something with the type void. But since a void does not represent anything (it represents nothing), the compiler cannot tell what this should be. You then use the equality operator to compare nothing to NULL. You cannot compare nothing to something, so this will generate an error.

In C, it is impossible to implement a function that would do something like this, simply because of the fact that you cannot tell what the type of the void* will be. You at least need to know the type your passed to your function and what type-specific value will be used to terminate the array. C does not offer this functionality, making the implementation of such a function impossible.

Upvotes: 1

Jens Gustedt
Jens Gustedt

Reputation: 78923

No, the way your are doing it is not possible, because to do pointer arithmetic (here the ++ and the -) the compiler has to know the size of the base type of the array.

Also void* is a pointer to void, that is to a "non-type". So *end has type void and you can't compare it to anything, in particular not to NULL, which could be a pointer type or an integer. Just use 0 if you compare a base type for being zero.

Before starting to even try to do this for pointers of any type, you should try the same for pointers to a known type, say unsigned or double. If you change your code with that in mind, it has good chances to work.

Upvotes: 1

Related Questions