1

i am trying to pass an int array as argument of a function who receives a void * array

The function is:

void foo(void *A[], unsigned int array_length)
{
    for (unsigned int i = 0; i < array_length; i++) {
        printf("%d ", (u32)(long)A[i]);
    }
}

Then i call like this:

int A[5] = {11, 12, 13, 14, 11};
foo((void *)A, 5);

but the printed array is: 11 13 11 -2015754187 -274447056 and i dont understand why this numbers are printed.

1
  • 1
    Maybe you meant void *A instead of void *A[] Commented Jan 2, 2021 at 1:49

3 Answers 3

2

Reading between the lines, Question 4.13: What's the total generic pointer type? in the C FAQ seems tangentially related:

There is no "total generic pointer type.".

The declaration void *A[] indicates that the function is expecting a list of void pointers, not a generic pointer to data elements. The kind of interface you seem to be seeking to implement can be found in the standard qsort function.

void qsort(void *base, size_t nel, size_t width,
       int (*compar)(const void *, const void *));

Note base points to the first element of the array to be sorted. Note also that the second and third arguments are essential for qsort to be able to to different elements of the array when invoking the comparison function compar. We assume compar knows what data type its arguments are supposed to be pointing to.

I recommend studying both the prototype of qsort and compar so that you can better frame the design you are after.

While the example below probably does not correspond directly to what you are trying to do, it should be decent starting point for brainstorming:

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

enum item_type {
    INTARR,
    INTARRLIST,
    DOUBLEARR,
    DOUBLEARRLIST,
};

struct item;

struct item {
    enum item_type type;
    size_t nelem;
    void *item;
};

void
print_int_arr(const int *x, size_t nelem)
{
    for (size_t i = 0; i < nelem; ++i)
    {
        printf("%d\n", x[i]);
    }
}

void
print_int_arr_list(const struct item *x[], size_t nelem)
{
    for (size_t i = 0; i < nelem; ++i)
    {
        const struct item *y = x[i];
        print_int_arr(y->item, y->nelem);
    }
}

void
print_item(struct item *x)
{
    switch(x->type)
    {
        case INTARR:
            print_int_arr(x->item, x->nelem);
            break;

        case INTARRLIST:
            print_int_arr_list(x->item, x->nelem);
            break;

        default:
            fprintf(stderr, "Unknown item type '%d'\n", x->type);
            exit(EXIT_FAILURE);
    }
}

int
main(void)
{
    int x[] = {1, 3, 5, 7, 9};
    struct item a = { INTARR, 5, x };
    struct item b = { INTARR, 3, x };
    struct item c = { INTARR, 1, x };
    struct item *d[] = { &a, &b, &c };
    struct item e = { INTARRLIST, 3, d };

    print_item(&a);
    print_item(&e);

    return EXIT_SUCCESS;
}
Sign up to request clarification or add additional context in comments.

Comments

0

Actually i need to be able to receive an array of any type because my intention is not to print them but to enqueue them in a queue.

What your foo function lacking is determining the type of data that should be passed as an argument, without it we cannot extract values properly from void*

Below is one of the ways to achieve what you are asking. Here I am passing the type of data and manipulating.

NOTE: This is not a generic function, it is just made to to handle some known types. you can add more types (pointers and structs etc.) and experiment.

I am printing the data just to be sure we are extracting what we passed, but you can use them as per your need.


#include <stdio.h>

typedef enum  { CHAR = 0, INT, FLOAT, STRING} DataType;

const char* getType(DataType t)
{
    if(t == CHAR)
        return "CHAR";
    else if(t == INT)
        return "INT";
    else if(t == FLOAT)
        return "FLOAT";
    else
        return "STRING";
}

void foo(void *A, unsigned int array_length, DataType type )
{
    printf("type is %s and len = %d\n", getType(type), array_length);
    
    switch(type)
    {
        case CHAR:
        {
            char *list = (char *) A;
            for (unsigned int i = 0; i < array_length; i++) {
                printf("%c ", list[i]);
            }
        }
        break;
        
        case INT:
         {
            int *list = (int *) A;
            for (unsigned int i = 0; i < array_length; i++) {
                printf("%d ", list[i]);
            }
         }
        break;
        
        case FLOAT:
         {
            float *list = (float *) A;
            for (unsigned int i = 0; i < array_length; i++) {
                printf("%.2f ", list[i]);
            }
         }
        break;
        
        case STRING:
         {
            char**list = (char**) A;
            for (unsigned int i = 0; i < array_length; i++) {
                printf("%s ", list[i]);
            }
         }
        break;
        
        default:
            printf("Invalid type");
            break;
    }
    putchar('\n');
}

int main()
{
    int arr_int[] = {11, 12, 13, 14, 11};
    //char arr_char[] = {"abcde"}; better way we have '\0' at the end
    char arr_char[] = {'a','b','c','d','e'};
    float arr_float[] = {11.20, 12.25, 13.70, 14.80, 11.15};
    char* arr_strings[] = {"abc","def","ghi","jkl","mno"};
    
    foo(arr_int, sizeof(arr_int) / sizeof(arr_int[0]), INT);
    foo(arr_char, sizeof(arr_char) / sizeof(arr_char[0]), CHAR);
    foo(arr_float, sizeof(arr_float) / sizeof(arr_float[0]), FLOAT);
    foo(arr_strings, sizeof(arr_strings) / sizeof(arr_strings[0]), STRING);
    
    return 0;
}

Comments

0

I think for foo you want an array of integers and not an array of void pointers.

Instead try?

void foo(int A[], unsigned int array_length)
{
    for (unsigned int i = 0; i < array_length; i++) {
        printf("%d ", A[i]);
    }
}

Or if you can't change foo's signature.

void foo(void *A[], unsigned int array_length)
{
    int* p = (int*) A;
    for (unsigned int i = 0; i < array_length; ++i) {
        // printf("%d ", *p++);
        printf("%d ", p[i]);
    }
}

4 Comments

Actually i need to be able to receive an array of any type because my intention is not to print them but to enqueue them in a queue.
See Nibblex's comment plus the above code. The issue is that an int could be 32 bits while a void pointer is maybe 64 bits. Depends on the system. I see two issues, you need to convert the int array to a pointer array then send to foo. The other issue is that you're deferencing the array of void pointers as if it was an int array.
The other thing to think about, is where theses void pointers live. Could be on the stack or could be on the heap. For example, take care if your queue is global and you're using stack void pointers. If on the other hand all void pointers are on the heap (allocated with malloc) and have one owner that that's a different story.
int A[] is not compatible with void *A[]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.