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.
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 **.
Looking at the source code for e2fsprogs and wanting to understand the use of internal memory routines. Allocating and freeing.
More to the point why use memcpy instead of direct handling?
Allocate
For example ext2fs_get_mem is:
/*
* Allocate memory. The 'ptr' arg must point to a pointer.
*/
_INLINE_ errcode_t ext2fs_get_mem(unsigned long size, void *ptr)
{
void *pp;
pp = malloc(size);
if (!pp)
return EXT2_ET_NO_MEMORY;
memcpy(ptr, &pp, sizeof (pp));
return 0;
}
I guess the use of a local variable is as not to invalidate the passed ptr in case of malloc error.
Why memcpy instead of setting ptr to pp on success?
Free
The memory is copied to a local variable, then freed, then memcpy on the passed pointer to pointer. As the allocation uses memcpy I guess it has to do some juggling on free as well.
It can not free directly?
And what does the last memcpy do? Isn't sizeof(p) size of int here?
/*
* Free memory. The 'ptr' arg must point to a pointer.
*/
_INLINE_ errcode_t ext2fs_free_mem(void *ptr)
{
void *p;
memcpy(&p, ptr, sizeof(p));
free(p);
p = 0;
memcpy(ptr, &p, sizeof(p));
return 0;
}
Example of use:
ext2_file_t is defined as:
typedef struct ext2_file *ext2_file_t;
where ext2_file has, amongst other members, char *buf.
In dump.c : dump_file()
Here we have:
ext2_file_t e2_file;
retval = ext2fs_file_open(current_fs, ino, 0, &e2_file);
It calls ext2fs_file_open() which do:
ext2_file_t file;
retval = ext2fs_get_mem(sizeof(struct ext2_file), &file);
retval = ext2fs_get_array(3, fs->blocksize, &file->buf);
And the free routine is for example:
if (file->buf)
ext2fs_free_mem(&file->buf);
ext2fs_free_mem(&file);
You cannot assign directly to the ptr parameter, as this is a local variable. memcpying to ptr actually writes to where the pointer points to. Compare the following usage code:
struct SomeData* data;
//ext2fs_get_mem(256, data); // wrong!!!
ext2fs_get_mem(256, &data);
// ^ (!)
You would achieve exactly the same with a double pointer indirection:
_INLINE_ errcode_t ext2fs_get_mem_demo(unsigned long size, void** ptr)
{
*ptr = malloc(size);
return *ptr ? 0 : EXT2_ET_NO_MEMORY;
}
but this variant requires the pointer being passed to to be of type void*, which is avoided by the original variant:
void* p;
ext2fs_get_mem_demo(256, &p);
struct SomeData* data = p;
Note: One additional variable and one additional line of code (or at very least one would need a cast)...
Note, too, that in the usage example ext_file_t should be a typedef to a pointer type to make this work correctly (or uintptr_t) or at least have a pointer as its first member (address of struct and address of its first member are guaranteed to be the same in C).
/* The 'ptr' arg must point to a pointer. */
can be read as "The ptr can point to pointer to ANYTHING".
It is a very simple malloc-wrapper in a library; to be useful it has to work for any type. So void * is the argument.
With a real type the function looks like this, with direct pointer assignment:
int g(unsigned long size, int **ptr)
{
void *pp;
pp = malloc(size);
if (!pp)
return 1;
*ptr = pp;
return 0;
}
The same *ptr = pp gives a invalid-void error with void *ptr as argument decalration. Somehow disappointing, but then again it is called void *, not any *.
With void **ptr there is a type warning like:
expected 'void **' but argument is of type 'int **'
So memcpy to the rescue. It looks like even without optimization, the call is replaced by a quadword MOV.
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.
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.
Alright here's the code:
//in another file
void **ptr; ptr = kmalloc(sizeof(void *) * 2);
*(ptr+0) = tf; //type trapframe *
*(ptr+1) = as; //type addrspace *
func(*ptr);
And here is that function:
void func(void *ptr) {
struct trapframe *parentTF = ptr[0];
struct addrspace *newAS = ptr[1];
//now I wanna do stuff with parentTF and newAS
}
And the error I get is:
warning: dereferencing `void *' pointer
Thanks for any help.
If I'm correctly understanding what you're trying to do, it seems like you need to change this:
void func(void *ptr) {
to this:
void func(void **ptr) {
and this:
func(*ptr);
to this:
func(ptr);
Note that *(ptr+0) and ptr[0] are synonymous, as are *(ptr+1) and ptr[1].
You're declaring ptr as a void ** but using it as a void *. They're different.
First cast the void pointer array to an array of the pointer type you want. i.e, you need to do such changes:
((trapframe **)ptr)[0] = tf; //type trapframe *
and another cast like this:
struct trapframe *parentTF = ((trapfname**)ptr)[0];
And what did you expect? The function's parameter ptr is a pointer to "something" (i.e. void). You dereference that pointer with ptr[0] and ptr[1], trying to extract "somethings". But the compiler doesn't know the type or size of "something".
What you probably want is this:
func(ptr);
and this:
void func(void** ptr)
{
...
}
In func, where ptr is declared as a void*, ptr[0] is the same as *ptr and ptr[1] is the same as *(ptr + 1). You're attempting to dereference a void pointer, as your compiler's telling you.
If you want to pass an array of void pointers to func, then you would make the following changes:
Change the signature of func to:
void func(void **ptr)
Change func(*ptr); to simply func(ptr); to pass the dynamically allocated array ptr to the function.
I also don't understand why you'd split the declaration and initialisation of ptr in the top snippet into two statements. Just have:
void **ptr = kmalloc(sizeof(void *) * 2);
or even:
void **ptr = kmalloc(sizeof(*ptr) * 2);
Your code screams wrongness because of the inconsistencies between the two files. In one, you access ptr[0] and ptr[1], while in the other you access *(ptr + 0) and *(ptr + 1) ... that happens not to be a source of error here because the two syntaxes mean the same thing, but using two different forms is bad style, reads badly, and is error prone. But then, in one file you declare void **ptr but in the other file you declare void *ptr -- that can't possibly be be right, since the two ptrs have the same semantics (they each point to an array of two elements, a tf and an as). In one file you have a function that takes a parameter called ptr, but in the other file you pass the contents of a variable named ptr ... again, since the two ptrs have the same semantics, this inconsistency must be wrong, and clearly it's the dereference that is wrong. Remove that and you're passing a void**, so that's what the parameter of func should be.
Code consistently and a whole class of errors will disappear from your code. You can code for 3 years or for 30 years, but it doesn't matter if you don't learn such fundamentals.