What is the use of void** as an argument in a function? - c

I have to implement a wrapper for malloc called mymalloc with the following signature:
void mymalloc(int size, void ** ptr)
Is the void** needed so that no type casting will be needed in the main program and the ownership of the correct pointer (without type cast) remains in main().
void mymalloc(int size, void ** ptr)
{
*ptr = malloc(size) ;
}
main()
{
int *x;
mymalloc(4,&x); // do we need to type-cast it again?
// How does the pointer mechanism work here?
}
Now, will the pointer being passed need to be type-cast again, or will it get type-cast implicitly?
I do not understand how this works.

malloc returns a void*. For your function, the user is expected to create their own, local void* variable first, and give you a pointer to it; your function is then expected to populate that variable. Hence you have an extra pointer in the signature, a dereference in your function, and an address-of operator in the client code.
The archetypal pattern is this:
void do_work_and_populate(T * result)
{
*result = the_fruits_of_my_labour;
}
int main()
{
T data; // uninitialized!
do_work_and_populate(&data); // pass address of destination
// now "data" is ready
}
For your usage example, substitute T = void *, and the fruits of your labour are the results of malloc (plus checking).
However, note that an int* isn't the same as a void*, so you cannot just pass the address of x off as the address of a void pointer. Instead, you need:
void * p;
my_malloc(&p);
int * x = p; // conversion is OK

Contrary to void *, the type void ** is not a generic pointer type so you need to cast before the assignment if the type is different.

void ** ptr
Here, "ptr" is a pointer to a pointer, and can be treated as a pointer to an array of pointers. Since your result is stored there (nothing returned from mymalloc), you need to clarify what you wish to allocate into "ptr". The argument "size" is not a sufficient description.

Related

Why is a double-void pointer required here? Dynamic "generic" array

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 **.

Assignment from void pointer to another void pointer

I want to copy the bits from one void * to another void *.
How can I do it?
I tried this:
static void* copyBlock(void* ptr) {
if (!ptr) {
return NULL;
}
int sizeOfBlock=*(int*)ptr+13;
void* copy = malloc(sizeOfBlock);
if (!copy) {
return NULL;
}
for(int i=0;i<sizeOfBlock;i++){
*(copy+i)=*(ptr+i);
}
return copy;
}
but I get: invalid use of void expression
You cannot dereference, perform pointer arithmetic, indexing a void pointer because it has no base type or object size. You must therefore cast the void pointer to the a pointer to the type of the data units you are copying so that the compiler will know the size of the data to copy.
All that said, you'd be better off using:
memcpy( copy, prt, sizeOfBlock ) ;
This design (storing block size inside of a block without any struct) seems dangerous to me, but I still know the answer.
*(copy+i)=*(ptr+i);
Here you get the error, because you can't dereference a void pointer. You need to cast it to pointer to something before. Like this:
((char *)copy)[i] = ((char *)ptr)[i];
You should use the memcpy function:
memcpy(copy, ptr, sizeOfBlock);
Depending on the compiler settings (you may be compiling as C++ and not as C), you may need to cast the pointers to a char pointer:
memcpy((char *) copy, (const char *) ptr, sizeOfBlock);
Note: The parameter of the function should be const char *ptr, to make sure you don't change the contents of ptr by mistake.

Clarifications about pointers use

I have a question for the exact meaning of a pointers phrase.
I have the following method:
myFunc(const void * p)
{
...
}
And it is being called by:
myStruct *st;
...
myFunc((char **)&st->arr);
I have experience with pointers, but in this case I still get lost with all these pointers and casting..
Can I get please an accurate explanation about how this case works?
Thanks
This seams to be bad quality code! Maybe not dangerous, as const appears in prototype.
myFunc(const void * p) accepts a pointer to anything and const should mean it won't touch it.
Now, st is a pointer to myStruct, so st->arr is the value of arr member and &st->arr is memory address of arr member. Assuming arr is an array, st->arr value is already a pointer.
So, (char**) is possibly the correct type of &st->arr, it is a pointer to a character array. And if it is the correct type, there is no need to cast!
You cast when you need to tell the compiler to handle your data as another data. It would make sense, in this case myFunc((const void *)&st->arr);
Anyway, without further information on myFunc, I belive that true programmer intention was myFunc((const void *) st->arr);
the address of st->arr is being converted to a char** (i.e. the address where to find a pointer to a char). myFunc accepts pretty much anything (void*) and you must be careful to pass it something it knows how to handle.
Internally, myFunc can do something like this:
struct myStruct{
char* arr;
};
void myFunc(const void* ptr){
char** cPtr = (char**) ptr;
(*cPtr)[1] = ...;
}
int main()
{
struct myStruct s;
...
myFunc((char **)&s.arr);
...
}
However, you should notice that this is extremely bad (as in "dangerouse") code.
You are calling the method myFunc with a double pointer char ** and the same you are catching with the const void *ptr . In C a void pointer can hold the other pointer types like(char */float */int */...), later on we can typecast them when we are using.
So here a void pointer can able to hold a double character pointer and you can typecast the void pointer to a double character pointer later on like
char **tempPtr = (char **)p;
Here const qualifier makes the pointer p as a constant data pointer, which means inside the function it wont change the data it is pointing to.

C cast syntax, how about complex casts?

I need some help in C syntax, more about C casting syntax.All information I found in web is about simple casts like (int) or (char) etc...I always get stuck in casting void* to a array or multi-dimentisional array or pointers of such things, but I never know how to do that! All that I do in these cases was trying things like (char []) or (char *[]) or (*char []) without any idea what I'm doing, until I get no errors about type casting.
Anybody have a thumb of rule to follow or some tips or tricks to do that?For example I have a arry of void pointers and I pass it to a function, how to turn it into array again?
main () {
int data1, data2;
char data3, data4;
void *function_data[] = {data1, data2, data3, data4};
some_function (function_data);
return;
}
some_function (void *data) {
void *function_d[4];
function_d = (void *[]) data; //It not work, how to cast data?
}
EDIT: I wrote wrong, I thinked that it wasn't important, so, I changed the variables data* of my code for better undestand.
Your problem is that void *function_d[4]; creates new array. You cannot assign other array to it. function_d should be of type void**.
The basic idea is to use the type definition of the intended type without the variable name and placed in parentheses as a cast to that type. For example:
int c;
c = (int) 4;
and
char * (*functionptr)(float, double);
functionptr = (char * (*)(float, double))myfunction;
Of course always assuming the type cast is possible and makes sense. Be aware: C doesn't prevent most nonsensical casts, so you'll have to take care yourself.
In your case, function_data is defined to be an array of pointers to void. Therefore, each data needs to be of type void **, as Keith already indicated.
By calling some_function with function_data as parameter, you're passing a pointer to function_data[0] into the function.
In order for your function to use it again as an array of 4 pointers to void, you would need to use a cast like you did, (void*[]). However, the array function_d is an array reserving also the space for four pointers, and you cannot change the function_d pointer (it is of type void * * const!). To do what you seem to want, you'll need a non-const pointer, like
void * * function_d = (void*[])data;
You may then still use it in the same way like function_data, using subscription like an array. function_d[2] will give you the value equal to *data3.
You cannot assign to an array object.
How are data1, data2, data3, and data4 declared?
void* is (or can be used as) a generic pointer type. That can give you tremendous flexibility, but it can also inhibit type checking.
function_data is an array of 4 pointers to void. In the call some_function (function_data), it's implicitly converted to void**, a pointer to the first element.
some_function expects a void*, not a void** -- but any pointer type (other than a function pointer) can be implicitly converted to void*, so the compiler doesn't complain about the call.
Here's a version of your program that's at least type-correct (I think).
#include <stddef.h>
void some_function(void **data, size_t count);
int main(void) {
void **data1, **data2, **data3, **data4;
void *function_data[] = { *data1, *data2, *data3, *data4 };
some_function (function_data,
sizeof function_data / sizeof function_data[0]);
return 0;
}
void some_function(void **data, size_t count) {
size_t i;
for (i = 0; i < count; i ++) {
/*
* do something with data[i], which is of type void*
*/
}
}
Note that data1 and friends are not initialized, so this program's behavior is undefined. I suspect you meant to write something like:
void *function_data[] = { &data1, &data2, &data3, &data4 };
but it's hard to tell just what you're trying to do.
If you really need the function to have a copy of the array, you can use memcpy() (you can't assign array values). For most purposes, though, it makes more sense to use pointers to access the original array. You'll need to make a copy if you want to modify the copy without affecting the original.
And I've corrected the declarations for main and some_function, and added a declartion for some_function to the top so it's visible when you call it.
You should always explicitly declare the return type for all your functions. In the 1990 version of C, you can omit it, and it will default to int (but it's still better to declare it as int explicitly). In the 1999 version of C, the type is required, and you can't call a function without a visible declaration.
Again, it's hard to tell from the code you've shown us just what you're trying to do, which makes it difficult to guess how to do it.
Several issues:
This isn't going to work:
int data1, data2;
char data3, data4;
void *function_data[] = {data1, data2, data3, data4};
because int and char are not compatible with void *. You could fix this as follows:
void *function_data[] = {&data1, &data2, &data3, &data4};
because int * and char * are compatible with void *.
When you pass function_data to some_function, the array expression is converted to a pointer value, so what some_function receives is a void **. You can use the subscript operator on the pointer as though it were an array:
some_function(function_data);
...
void some_function(void **data)
{
int *x = data[0]; // remember, we stored the *addresses*
int *y = data[1]; // of data1, data2, data3, and data4;
char *a = data[2]; // since the type of data is void **,
char *b = data[3]; // the type of data[i] is void *.
...
}
IOW, you don't need to cast data to an array type in order to use it like an array.

Problem using void pointer as a function argument

I can't understand this result...
The code:
void foo(void * key, size_t key_sz) {
HashItem *item = malloc(sizeof(HashItem));
printf("[%d]\n", (int)key);
...
item->key = malloc(key_sz);
memcpy(item->key, key, key_sz);
}
void bar(int num) {
foo(&num, sizeof(int));
}
And I do this call: bar(900011009);
But the printf() output is:
[-1074593956]
I really need key to be a void pointer, how can I fix this?
I think you need this:
printf("[%d]\n", *(int*)key);
The key is a void pointer to the int, so you first need to cast to an int pointer, then dereference to get the original int.
If you cast the pointer to int, you are getting the address as the value. You need to dereference void pointers like any other. Only you cannot directly dereference void *, so you must first cast it to a pointer of the correct type, here int *. Then dereference that pointer, i.e. *((int *)key) (extra parentheses to clarify the precedence).

Resources