Question

I have a fixed-size array declared:

int vals[25];

And I'd like to send the array to a function which will assign the values of vals:

bool FetchValueArray(char* source, char* name, char* typeFormat, int count, void** destination)
{
    int i;
    char *t;
    t=strstr(source,name);
    if (t)
        if (destination != NULL)
        {
            for (i = 0;i < count;i++)
                sscanf(t,typeFormat,destination[i]);
                return true;
        }
    return false;
}

This will essentially read everything at after a certain search string. For example:

FetchValueArray(source,"CONFIG=","%d",15,vals);

Where "CONFIG=" is in plain text, followed by 15 tab separated numeric values.

There's something here I'm far from grokking about indirection and fixed aized arrays thus I'd like to know if a fixed sized array can be sent as a parameter as void** (even if there is the leap of faith that the size of the array will be respected. Different issue.)


tl;dr version

int vals[25];
bool foo(int size,void** d);
foo(25,vals);

Why is this not allowed?

Was it helpful?

Solution

Arrays decay into pointers to their first elements, and pointers to any type can be implicitly cast to void*. Secondly, in order for array access to work properly, FetchValueArray needs to know how large each array element is. You're trying to pass a void**, which is a pointer to a void*, so the array access treats each element as if it had the size of a void*, which is wrong -- your array elements have size int, which is not necessarily the same as the size of a void*.

So void** is wrong. You instead need to pass in void*, which means "pointer to unknown type". You can't use array indexing on a void*, since the compiler doesn't know the size of the underlying pointed-to type. You need to help it out. For example:

bool FetchValueArray(char* source, char* name, char* typeFormat, int count, void* destination, size_t destElementSize)
{
    ...
    sscanf(t, typeFormat, (char*)destination + destElementSize * i);
    ...
}
...
FetchValueArray(source, "CONFIG=", "%d", 15, vals, sizeof(vals[0]));

Here, we're performing the array indexing manually -- we're casting the void* to char*, which has a known pointed-to size (1 byte), and then performing the array offset by multiplying by the per-element size. The result is a pointer to the proper memory location, which is what sscanf expects.

Be very careful here, though -- I think you should reconsider your design. The compiler doesn't know the semantics of your function, so it can't verify that you're passing the proper arguments. It's very easy to insert an accidental security vulnerability without realizing it here. Think about if you might be better off with a different design that the compiler can verify more thoroughly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top