Reputation: 9211
Say I want to dynamically allocate an array that can hold any data, i.e. using void**
as my type, in C. Then, rather than re-writing the pointer arithmetic logic each time, I want a simple function that returns the address of an element. Why is it that I cannot use this function in an assignment (i.e., so I can set, as well as get the element's value)?
Here's some example code:
#include <stdio.h>
#include <stdlib.h>
void printIntArray(void** array, size_t length) {
printf("Array at %p\n", array);
while (length--) {
printf(" [%zu] at %p -> %p", length, array + length, *(array + length));
if (*(array + length)) {
printf(" -> %d", *(int*)*(array + length));
}
printf("\n");
}
}
void* getElement(void** array, size_t index) {
return *(array + index);
}
int main(int argc, char** argv) {
const size_t n = 5;
size_t i;
/* n element array */
void** test = malloc(sizeof(void*) * n);
i = n;
while (i--) {
*(test + i) = NULL;
}
/* Set element [1] */
int testData = 123;
printf("testData at %p -> %d\n", &testData, testData);
*(test + 1) = (void*)&testData;
printIntArray(test, n);
/* Prints 123, as expected */
printf("Array[1] = %d\n", *(int*)getElement(test, 1));
/* Something new in [2] */
/* FIXME lvalue required as left operand of assignment */
int testThing = 456;
getElement(test, 2) = (void*)&testThing;
printIntArray(test, n);
return 0;
}
It wouldn't be the fist time this question has been asked, but the answer is usually along the lines of "you are trying to assign something to a function, rather than the return value of a function, which is not allowed". Fair enough, but can one get around this? I'm somewhat confused!!
Upvotes: 0
Views: 846
Reputation: 70911
Implement getElement()
like this:
void ** getElement(void ** ppv, size_t index) {
return ppv + index;
}
And use it like this:
*getElement(test, 2) = &testThing;
If you'd use a macro you could even go the way you intended:
#define GET_ELEMENT(ppv, index) \
(*(ppv + index))
Use it like this:
GET_ELEMENT(test, 2) = &testThing;
Upvotes: 2
Reputation: 17573
Assignment to a void is not allowed so you will need to cast the void pointer to some other type of pointer for any kind of an assignment.
In other words,
void *vPtr = malloc(35);
*((int *)vPtr) = 5; // legal since cast void * to int *
*vPtr = 5; // illegal since size of the memory location pointed to is unknown.
The same principle applies to a function that returns a void pointer.
You just have to cast the pointer returned by the function to a type that allows assignment.
A simple example that compiles in Visual Studio 2005 is.
void *xPtr (int *pp)
{
return pp;
}
void jj ()
{
int jjj;
*( (int *)xPtr(&jjj)) = 6;
}
Where as if you change the function jj()
to
void jj ()
{
int jjj;
*(xPtr(&jjj)) = 6;
}
you will see compile errors such as
1>c:\fileobject.c(191): error C2100: illegal indirection
1>c:\fileobject.c(191): warning C4047: '=' : 'void *' differs in levels of indirection from 'int'
1>c:\fileobject.c(191): error C2106: '=' : left operand must be l-value
Upvotes: 2
Reputation: 27854
getElement(test, 2) = (void*)&testThing;
This won't ever work. You cannot assign a value to a function. Use this:
test[2] = (void*)&testThing;
Note that getElement(test, 2)
returns NULL
, it is not a pointer to the element index 2
of your array test
, it's its value (that is also a pointer, but not the one you need). No matter what you do with the information getElement(test, 2)
provides you, you can never use it to change test[2]
.
Say its a situation where the caller don't have access to test
, you would have to write a setElement()
function.
void setElement(void** array, size_t index, void* value) {
array[index] = value;
}
...
setElement(test, 2, (void*)&testThing);
Upvotes: 1
Reputation: 638
C uses pointers to fake what other languages call reference... Here is an example of what you are trying to do:
typedef struct
{
int x;
} st;
st f()
{
st p;
p.x = 20;
return p;
}
int main()
{
f().x = 9;
}
You are returning a value from a function... you need to assign that value to something before you use it. Yes, a pointer follows the same rule, the difference is that it's value is the address of something... so you would have to assign the return of your function to a void *variable and to what you wanna do on this variable.
In my example, to make it work you need to something like:
int main()
{
st v = f();
v.x = 9;
}
Same logic goes for your pointer
Upvotes: 0