0

I'm trying to a function that takes as arguments an array (in this case it's void since the goal is to make it "compatible" with any numerical types), its size and the function that it wants to evaluate. Everything seemed to be working fine, since it compiled with no errors, but it returned (printed) weird values.

Sure enough, after priting in each function, the pointer was pointing to some weird numbers in my memory and not actually the array I passed to the countSelect function (and then the minor functions).

I'm new to pointers and playing with C at this level, and would massively appreciate someone more experienced telling me what's actually wrong (and suggestions for improving it/avoiding it).

#include <stdio.h>

int selNegInt(void * num) {
    int * pointToNum = (int *) num;
    //printf("1 - %d\n", *pointToNum);
    return *pointToNum < 0; //or *((int *) num)
}

int selEvenInt(void * num) {
    int * pointToNum = (int *) num;
    //printf("2 - %d\n", *pointToNum);
    return *pointToNum % 2 == 0;
}

int selOddIn(void * num) {
    int * pointToNum = (int *) num;
    //printf("3 - %d\n", *pointToNum);
    return *pointToNum % 2 != 0;
}

int selGt10In(void * num) {
    int * pointToNum = (int *) num;
    //printf("4 - %d\n", *pointToNum);
    return *pointToNum > 10; 
}

int countSelected(void * a , int size, int sizelem, int (*select)(void *)) {
    int total=0;
    for (int i=0; i<size/sizelem; i++) {
        if (select(a+i)) total++;
    }
    return total;
}

int main(void) {

    int a[] = {-1, 24, 0, 2141, -241, 2415};

    printf("Num negs = %d\n", countSelected(a, sizeof(a), sizeof(*a), selNegInt));
    printf("Num evens = %d\n", countSelected(a, sizeof(a), sizeof(*a), selEvenInt));
    printf("Num odds = %d\n", countSelected(a, sizeof(a), sizeof(*a), selOddIn));
    printf("Num greater than 10 = %d\n", countSelected(a, sizeof(a), sizeof(*a), selGt10In));

    return 0;
}

2 Answers2

2

Actually the compiler is warning you about the problem (-Wpointer-arith), because you are trying void* + 2, so it is a weird pointer arithmetic operation (actually it is undefined behaviour, under the hood, it is adding sizeof(void), check this: Pointer Arithmetic). So you'll have to cast the void pointer in order to indicate its size:

if (select((int *)a+i)) total++;

Jose
  • 3,306
  • 1
  • 17
  • 22
-1
if (select(a+i)) total++;

Change that line to this:

if (select(a+i * sizelem)) total++;

Normally when adding values to pointers the compiler automatically multiplies the number by the size of an element so everything works properly, but since it's a void pointer the compiler doesn't know the size of an element. Therefore, you have to multiply by sizelem to do it yourself.

Aplet123
  • 33,825
  • 1
  • 29
  • 55
  • Ah, so because it's a void (and doesn't have a data size like int or stuff) it's necessary to do a+i * sizelem? Is it because if I do a+i on an int it's equivalent to a[i] but on a void it's just going to the next memory position since it doesn't know the size that each "index" occupies? – reallybadprogrammer Mar 28 '20 at 18:58
  • I mean `int* p = ..; b = *(p + 2);` etc. – trojanfoe Mar 28 '20 at 18:58
  • Exactly. When you do `a+i` on an int pointer the compiler automatically converts it to `a+i*sizeof(int)`, but since it's a void pointer the compiler doesn't know the size so it can't scale it. – Aplet123 Mar 28 '20 at 18:59
  • Thank you, perfectly understood! @Aplet123 – reallybadprogrammer Mar 28 '20 at 19:00
  • Glad I could help you! – Aplet123 Mar 28 '20 at 19:00
  • Although some compilers will treat `void *` arithmetic as `char *`, is not portable C code, and is relaying on compiler extensions (like https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html). The right solution is to cast pointer to its correct type (int * in this case). – eugenioperez Mar 31 '20 at 10:06