1

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!

aurelienC
  • 1,113
  • 3
  • 12
  • 22
  • 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. – chux - Reinstate Monica Dec 08 '15 at 17:37
  • I am not sure that what you want to do is possible. In order for your function to count the number of elements in the array, it must have a way of knowing what type the array is, because that's the only way that the C compiler has to know where each element begins and the next one ends. – Tim Pierce Dec 08 '15 at 17:40
  • This is not possible with a function but you could use a macro, **if** you are sure that you have an array and not just a pointer: https://stackoverflow.com/questions/37538/how-do-i-determine-the-size-of-my-array-in-c – Jens Gustedt Dec 08 '15 at 17:43
  • I think one way to do it is to use the **call by reference mechanism**, first store base address of array in a pointer and send it to function and then proceed to count elements till null character with the help of pointer to access values of the array whose length has to be calculated. – Cherubim Dec 08 '15 at 17:44

5 Answers5

3

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;
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • I didn't even realised `NULL`can only be assigned to pointers.
    But for what i have seen if the comparison with `NULL` is made with a pointer of any type it should work isn't it?
    – aurelienC Dec 08 '15 at 19:28
  • @aurelienC Yes,If `array` is a pointer to an array of pointers. The compare test is simply `*ptr == NULL`. Code could reasonable assume all pointers are the same size and use `ptr++`. Pedantic code would pass the size of the pointer. But now we have a new question. – chux - Reinstate Monica Dec 08 '15 at 19:33
  • 1
    @aurelienC Detail: "`NULL` can only be assigned to pointers" is not quite correct. Typical code only assigns `NULL` to a pointer. `intptr_t` is an integer type that one can save `NULL`, and other special situations occur, but best to only assign `NULL` to pointers. – chux - Reinstate Monica Dec 08 '15 at 19:40
  • 2
    @aurelienC, *can* isn't right, take it as *should*. `NULL` is designed as being a null pointer constant. That it also may, on some platforms, be assigned to an integer type is just an artifact. Be sure that for integer types you always use `0` so your intent is clear, and also such that it works even on platforms where you can't assign `NULL` to integers. – Jens Gustedt Dec 08 '15 at 19:48
1

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.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
1

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.

Shadowwolf
  • 973
  • 5
  • 13
  • It seems like the main issue with what i have made is that i compare what the `void*`point to and not the `void*`itself with NULL. – aurelienC Dec 08 '15 at 19:32
  • If you compare the argument (the void*) to NULL, you won't be able to pass any array to your function. The comparison will simply always return false. – Shadowwolf Dec 08 '15 at 20:05
1

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

linluk
  • 1,650
  • 16
  • 33
-1

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.

Ian Abbott
  • 15,083
  • 19
  • 33
  • I have seen on another question on this site that this method wan't work on an array passed as a function parameter. – aurelienC Dec 08 '15 at 19:35
  • Well yes, you cannot pass an array to a function anyway (unless it's embedded in a `struct` or `union`), but since OP wanted a function whose sole purpose seemed to be counting the elements of an array, and since such a function is impossible, my answer described how to determine the number of elements in an actual array. – Ian Abbott Jun 08 '16 at 11:42