user2071938
user2071938

Reputation: 2255

C pass void pointer array to function

I want to pass a void pointer array to a function which fills it with the result it works fine with integer but I have troubles returning char*

int function(void *arr[]);
int main(void) {
    void *arr[3];
    function(arr);
    printf("%d\n", *(int *)&arr[0]);
    printf("%d\n", *(int *)&arr[1]);
    printf("%s\n", (char *)&arr[2]);
}
int function(void *arr[]){
    arr[0] = (void*)(int)4;
    arr[1] = (void*)(int)6;
    char* test = "abc";
    arr[2] = (void*)test;
    return 0;
}

for the String I don't get the right value

Upvotes: 0

Views: 1355

Answers (3)

tonyjosi
tonyjosi

Reputation: 827

arr[0] = (void*)(int)4;

The above line cast the integer 4 as void pointer (address) and stores it in the array arr as pointer address. I guess that's not what you wanted.

In order to access data using a void pointer the way you want, first make it point to a valid memory address, which will hold the data when the function exits. You have to be careful while assigning memory address to a void pointer inside a function, all variables in that function's stack (local variables) will be popped off the from the stack when the function exits, making that memory addresses invalid. Only use static (or global) or dynamic memory while assigning the memory address to your pointer inside the function, if you want to use it outside the function.

Upvotes: 1

n. m. could be an AI
n. m. could be an AI

Reputation: 119847

arr has type void(*)[3].

arr[0] has type void*. The fact that it stores a suitably converted value of 4 is irrelevant.

&arr[0] has type void**.

(int *)&arr[0] has type int*, but it points to an object of type void* instead of pointing to an object of type int. This is not what pointers normally do. You can have such a pointer, but the only thing you can legally do with it is convert it back to the right type, in this case void**. You are not doing that.

*(int *)&arr[0] has type int.

Here you are accessing an object of type void* through an lvalue of type int. This is undefined behaviour. Don't do that.

If you want to convert arr[0] back to int, just do that:

printf("%d\n", (int)arr[0]);

Likewise, if you want to convert arr[2] back to char*, do just that:

printf("%s\n", (char*)arr[2]);

Upvotes: 2

KamilCuk
KamilCuk

Reputation: 140960

You may pass an array of voids, and assign that array elements to a dynamically allocated memory region that stores the pointed-to value.

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

int function(void *arr[]){    
    arr[0] = malloc(sizeof(int));
    if (arr[0] == NULL) goto ERR_MALLOC_0;
    *(int*)arr[0] = 4;

    arr[1] = malloc(sizeof(int));
    if (arr[1] == NULL) goto ERR_MALLOC_1;
    *(int*)arr[1] = 6;

    const char *const test = "abc";
    arr[2] = malloc(strlen(test));
    if (arr[2] == NULL) goto ERR_MALLOC_2;
    strcpy(arr[2], test);

    return 0;

    // remember about error checking
    free(arr[2]);
    ERR_MALLOC_2:
    free(arr[1]);
    ERR_MALLOC_1:
    free(arr[0]);
    ERR_MALLOC_0:
    return -1;
}

int main(void) {
    void *arr[3];
    int err = function(arr);
    if (err == -1) abort();

    // & is the address of element, not it's element
    printf("%d\n", *(int*)arr[0]);
    printf("%d\n", *(int*)arr[1]);
    printf("%s\n", (char*)arr[2]);

    // remember to free memory
    for (int i = 0; i < 3; ++i) {
        // funny how we do not need to know the effective type
        free(arr[i]);
    }
}

But such function is just plainly confusing and will result in many, many bugs and problems. Instead just actually use variables of proper type:

#include <stdlib.h>
#include <string.h>

int function(int *val1, int *val2, char **string) {
    *val1 = 3;
    *val2 = 6;
    const char *test = "abc";
    *string = malloc(strlen(test));
    if (*string == NULL) return -1;
    strcpy(*string, test);
    return 0;
}

int main(void) {
    int val1; 
    int val2;
    char *string;
    int err = function(&val1, &val2, &string);
    if (err == -1) abort();

    printf("%d\n", val1);
    printf("%d\n", val2);
    printf("%s\n", string);

    free(string);
}

If you are really striving for implementing some virtual representation and operations on different data types, using plain "array of void pointers" will get you nowhere, because such array doesn't know what is the underlying type of the value that is being stored - you, as a programmer, have to know what is inside that array (ie. that arr[0] is an int and arr[2] is a char*), so as you know it you might as well just use variables of proper types from the start.

Upvotes: 1

Related Questions