I am trying to use a double void pointer but I am a little bit confused about the usage.
I have a struct that contains a void ** array.
struct Thing{
void ** array;
};
struct Thing * c = malloc (sizeof(struct Thing));
c->array = malloc( 10 * sizeof(void *) );
So If I want to assign a different object to each pointer and try to retrieve the value
// Option 1
*(c->array + index) = (void *) some_object_ptr;
// Option 2
c->array[index] = (void *) some_object_ptr;
then, I have another function that gives (void *) item that points to each cell, not the some_object_ptr.
If I want to retrieve the value which pointed to by some_object_ptr,
should I do
function return type is 'void *' and takes argument 'void *'
// Option 3
return (void**) item
// Option 4
return *((void**)item)?
the weird thing is that when I used array the array subscript method I couldn't use option 4, only option 3; and when I used *(c->array + index) I could only use opt.4. and not opt.3. ..
Can anyone please tell me about this? If I am making any invalid assumptions, then could you please correct me?
A void ** is just a pointer to a pointer to memory with an unspecified type. You can only dereference it once (since you can't dereference a void *). However, apart from that, it is basically like any other pointer type. If it helps you, think of it the same way as you would with int *.
So, in your specific situation, we have:
void** array;
int arrayLen = 10;
array = (void**)malloc(arrayLen * sizeof(void*));
some_type_t* some_object_ptr;
// The following two assignment are equivalent since in C,
// array[index] <=> *(array + index)
array[index] = (void*)some_object_ptr;
*(array + index) = (void*)some_object_ptr;
Then array is a pointer to the whole array, while *array is a pointer to the first element, since it is equivalent to array[0].
One quick hint about pointers: if you are casting it, you are probably doing something wrong.
As for your question. I am not sure what item is in your problem. In your first part you've already discovered how to acces a member in your array. You could simply use it:
void *get_item(Thing *c, int index)
{
return *(c->array + index); // or return c->array[index];
}
If you need the address of the pointer at index:
void **get_item_cell(Thing *c, int index)
{
return c->array + index; // or return &c->array[index];
}
In the second part, you don't dereference the pointer (for + option), or take the address of array result, since it automatically dereferences it.
EDIT:
I think I now know what you want. You have a function similar to my second one above, but it is:
void *get_item_cell(Thing *c, int index)
{
return (void *)(c->array + index);
}
You want to dereference the value returned from this function, and access the object. In that case, you can only use Option 4 safely. Since you don't have the index, you cannot move to any other cell (you don't know if you are at the end of the array, or at the beginning - so no additions or subtractions). You can only fix the mistake of the above function: cast to void **, and then dereference it: *(void **)item. This will give you a void *. If you want to access the object pointed from this cell, you need to cast that to the correct type as well: some_object_ptr *obj = *(void**)item.
The fact you are working with void* and void** doesn't matter, pointer arithmetic still works fine, so both options you wrote are correct.
Here's an example:
struct Thing
{
void ** array;
};
struct Object
{
int i;
char c;
};
int main ()
{
struct Thing * c = malloc (sizeof(struct Thing));
c->array = malloc(10 * sizeof(void*));
struct Object * o = malloc (sizeof(struct Object));
o->i = 2; o->c = 'a';
*(c->array + 2) = o;
printf("Object: i = %d, c = %c\n", ((Object*)c->array[2])->i, ((Object*)c->array[2])->c);
free(o);
free(c->array);
free(c);
return 0;
}
Since it's void* you can put there pointer to whatever, just don't forget it to cast to original type before using it ;)
Almighty push!
any_type x ;
void * v = * ( void * * ) & x ;
almighty pull!
void * v ;
any_type x = * ( any_type * ) & v ;
beware of losing/gaining digits
Related
I tried to implement a form of collections-library. I do it all the time, when learning a new language, because it teaches most of the language details.
So, I started with a form of "generic" dynamic array. Well it is not really generic, because it just holds pointers to the actual data.
But to be honest, I don't fully understand, why I need a double void pointer here.
The Vector struct defined in my header file (I declared every method and #include in the header file, but I omitted this here to keep the code readable. I also ommitted some bounds checks)
typedef struct {
size_t capacity; //the allocated capacity
size_t length; //the actual length
void **data; //here I don't fully understand, why I need a double pointer.
} Vector;
Here is my implementation of a few methods, where the compiler complains when I use a single void pointer in my struct, so void *data instead of void **data.
#include "utils.h"
const size_t INITIAL_SIZE = 16;
//Creates a new empty vector.
Vector *vec_new(void) {
printf("sizeof Vector is: %ld", sizeof(Vector));
Vector *vec = malloc(sizeof(Vector));
vec->length = 0;
vec->capacity = INITIAL_SIZE;
void *data = calloc(INITIAL_SIZE, sizeof(void*));
if(data == NULL) {
free(vec->data);
fprintf(stderr, "Error allocating memory.");
exit(EXIT_FAILURE);
}
vec->data = data;
return vec;
}
//This method appends the specified value at the end of the vector.
void vec_push(Vector *vec, void *data) {
if(vec->length == vec->capacity-1) {
vec_resize(vec);
}
vec->data[vec->length] = data;
vec->length += 1;
}
//gets the value at the specified index or NULL if index is out of bounds.
void *vec_get(Vector *vec, size_t index) {
return vec->data[index];
}
//Resizes the vector to 1.5x its current capacity.
void vec_resize(Vector *vec) {
vec->capacity *= 1.5;
void *data = realloc(vec->data, sizeof(void*) * vec->capacity);
if(data == NULL) {
free(vec->data);
fprintf(stderr, "Error allocating memory.");
exit(EXIT_FAILURE);
}
vec->data = data;
}
It seems like here is where the magic happens, which i do not yet understand:
void *data = malloc(...);
vec->data = data;
Malloc/calloc return a void pointer, so i either have to declare an actual type or just using the returned void pointer. So the first line is clear.
vec->data is, under the assumption I do not use a double pointer in the struct definition equivalent to (*vec).data as far as I understand it. So basically this line should assing a void pointer to a void pointer.
Can maybe someone explain it to me in simple terms, why exactly a single void pointer is not enough here or where I might misunderstand something.
But to be honest, I don't fully understand, why I need a double void pointer here.
Some background first - maybe you already know that:
A pointer of the type someType * is a pointer to some variable of the type someType or to an array of variables of the type someType.
A pointer of the type someType ** is a pointer to a variable of the type someType * - this means: A pointer to a pointer to a variable of the type someType.
A pointer of the type void * is a pointer to anything; because the compiler does not know to what kind of element this pointer points to, it is not possible to access such an element directly.
In contrast to this, it is known what variable a pointer of the type void ** points to: It points to a variable of the type void *.
Why you need void** in this position:
The key are the lines:
vec->data[vec->length] = data;
...
return vec->data[index];
In these lines, the code accesses the data vec->data points to. For this reason, vec->data cannot be void * but it must be xxx * while xxx is the type of data the pointer vec->data points to. And because vec->data points to a pointer of the type void *, xxx is void * so xxx * is void **.
vec->data = data;
Your observation is correct: vec->data is of the type void ** and data is of the type void *.
The reason is that malloc() returns some memory and the compiler does not know which kind of data is stored in this memory. So the value returned by malloc() is void * and not void **.
In the automotive industry, you would use an explicit pointer cast like this:
vec->data = (void **)data;
The expression (xxx *)y tells the compiler that the pointer y points to some data of the type xxx. So (void **) tells the compiler that the pointer points to an element of the type void *.
However, in desktop applications you often don't write the (void **).
If you have a pointer of the type
T *p1;
where T is some type specifier as for example void then pointer to this pointer will be declared like
T **p2 = &p1.
In this call of calloc
calloc(INITIAL_SIZE, sizeof(void*))
you are going to allocate an array of pointers of the type void *. The function returns a pointer to the first element of the allocated array. So you need to write
void **data = calloc(INITIAL_SIZE, sizeof(void*));
To make it more clear let's assume that you need to allocate dynamically an integer array. In this case you will write
int *data = calloc( INITIAL_SIZE, sizeof( int ) );
So dereferencing the pointer data like *data you will get an object of the type int more precisely the first element of the allocated array.
When elements of the array have the type void * then dereferencing the pointer data like *data you must to get a pointer of the type void * (the first element of the allocated array). So to make the operation correct the pointer data shall have the type void **.
I'm trying to get struct's address.
I want to get address in an int *, and I want to change address by adding numbers to the int *. I tried several ways, but I can't solve it.
struct num_d {
unsigned char data;
unsigned char pad1;
unsigned char pad2;
unsigned char pad3;
};
struct num_d **m = malloc(sizeof(struct num_d *) * row);
for (int i = 0; i < row; i++)
{
m[i] = malloc(sizeof(struct num_d) * col);
}
How can I get m[0][0]'s address in an int *?
first things first lets typedef your struct, so we can type less and be more clear:
typedef struct num_d num_d;
void pointer
A pointer to void is a "generic" pointer type. A void * can be converted to any other pointer type without an explicit cast. we cannot de-reference a void * or do pointer arithmetic with it; you must convert it to a complete data type pointer first (like int* e.g.) then do the de-refrence or the pointer arithmetic.
Now, malloc() return a void* which points to the allocated heap buffer (if malloc successed in allocation other wise null is the return value).
you code become:
num_d** m = malloc(sizeof(num_d*) * row); /*m is an array of void* pointers (not initialized)*/
for (int i = 0; i < row; i++)
{
m[i] = malloc(sizeof(num_d) * col); /*in each element in m you have a void* that points to struct num_d on the heap*/
}
the sizeof(void*) is the same as sizeof any pointer (except function pointers in some machines/os).
putting it all together
How can I get m[0][0]'s address in an int *?
This is a wrong question! because m is an array of void* to "num_d structs" (holding the num_d heap address).
if you want the start address of the i-th num_d struct in the array m, then, just return the void* in the index i in this array m[i]. and if you want to cast it just cast it (no need actually) just assign it:
int* ptr = m[i];
Take in mind that compilers will warn you, regarding the assignment above (but this assignment is supported and legal) :
warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
or (no need again):
int* ptr = (int*)m[i];
I don't know why you need such behavior, it makes more sense to cast to num_d*
if you want the address of the first data member in the struct num_d, then you must cast to the appropriate data type to get the expected data:
unsigned char data = ((num_d*)m[i])->data;
unsigned char* p_data = &((num_d*)m[i])->data;
You don't need to have the address in an int* in order to be adding to it. The way that [] works, is that it adds to the pointer and dereferences.
You can just add to *(m[0] + 1) to get the second element.
How about:
int *ptr = (int *) m[0];
struct info
{
int val;
};
void copy(struct info ** dst, struct info * src)
{
*dst = (struct info *)malloc(sizeof(struct info));
**dst = *src;
}
int main()
{
struct info *a, *b;
a = (struct info *)malloc(sizeof(struct info));
a -> val = 7;
copy( , );
a -> val = 9;
printf("%d", b->val);
}
I have tried (b, a), (*b, *a), (b, *a) and so one but the argument is always unexpected by the compiler. Have been trying for an hour with no result - just a half melted brain.
The first argument is supposed to be a pointer to a pointer. Since b is a pointer, you need to take its address, which is &b.
The second argument is supposed to be a pointer. a is a pointer, so you just pass it directly.
copy(&b, a);
* is for indirecting through a pointer to access what it points to. That's the exact opposite of what you want, which is to get a pointer to the variable itself. You use * inside the copy function to access what the pointers given point to.
BTW, you should also see Do I cast the result of malloc?
And don't forget to free the structures when you're done using them.
can someone help with this piece of code? I leaved out check of allocations to keep it brief.
typedef struct {
int x;
int y;
} MYSTRUCT;
void init(MYSTRUCT **p_point);
void plusOne(MYSTRUCT **p_point, int *p_size);
int main()
{
MYSTRUCT *point;
int size = 1;
init(&point);
plusOne(&point, &size);
plusOne(&point, &size);
point[1]->x = 47; // this was the problem
point[1].x = 47; // this is solution
return 0;
}
void init(MYSTRUCT **p_point)
{
*p_point = (MYSTRUCT *) malloc( sizeof(MYSTRUCT) );
}
void plusOne(MYSTRUCT **p_point, int *p_size)
{
(*p_size)++;
*p_point = realloc(*p_point, *p_size * sizeof(MYSTRUCT) ); // also calling to the function is fixed
}
I don't understand why index notation doesn't work after calling to functions.
This is because you are not multiplying the p_size by sizeof(MYSTRUCT) in the call of realloc, and not assigning the results back to p_point:
*p_point = realloc(*p_point, *p_size * sizeof(MYSTRUCT));
Notes:
You do not need to cast the result of malloc or realloc in C.
For consistency, consider passing &size to init, and set it to 1 there.
You have some type confusion going on... Here:
MYSTRUCT *point;
you declare point to be a pointer to a MYSTRUCT structure (or an array of them).
The syntax point[i] is equivalent to *(point + i) - in other words, it already dereferences the pointer after the addition of the appropriate offset, yielding a MYSTRUCT object, not a pointer to one.
The syntax p->x is equivalent to (*p).x. In other words, it also expects p to be a pointer, which it dereferences, and then yields the requested field from the structure.
However, since point[i] is no longer a pointer to a MYSTRUCT, using -> on it is wrong. What you are looking for is point[i].x. You could alternatively use (point + i) -> x, but that's considerably less readable...
I'm trying to write a function that takes a void pointer to an int and then doubles the int, and puts it back into the memory location:
void doubleNumber(void *number){
number = &((*((int*)(number))) * 2);
}
So first I cast it into an int * from a void *, then I deference the int * to get the value, then I multiply by 2 and then I get the address of that to put it back into the pointer.
Can anyone give me tips on why my logic is not working?
Thanks
I'd write it like this:
void doubleNumber(void *number){
*(int*)number *= 2;
}
First of all cast number to be of type int*. Then dereference the pointer. Then double it.
The problem with your code is that you are assigning the pointer rather than the pointee.
Step 1:
void doubleNumber(int *value) {
*value = 2 * (*value);
}
Step 2:
void doubleNumber(void *value) {
int * ivalue = (int *)value;
*ivalue = 2 * (*ivalue);
}
Firstly, arguments to functions in C are passed by value, so modification of number will have no effect.
Secondly, even if it did, you should allocate some memory for the value first. Only then can you return a pointer to this place in memory.
A value (such as 2) has no address.
Instead, simply write:
* (*int)number = *(int*) number) * 2;
or, shorter:
* (*int)number *= 2;