incompatible pointer type in C - c

so I'm trying to pass a type double * to a function that accepts void ** as one of the parameters. This is the warning that I am getting.
incompatible pointer type passing 'double **' to parameter of type 'void **'
Here is a snippet of my code.
int main( void )
{
// Local Declaration
double *target;
// Statement
success = dequeue(queueIn, &target);
}
Here's the prototype declaration of the function.
int dequeue ( QUEUE *queue, void **dataOutPtr );
I thought that if I passed target as a two level pointer that it would work, but I guess I'm wrong. Can someone please explain to me how come i'm getting this warning?

Even though all other pointer types can be converted to and from void * without loss of information, the same is not true of void ** and other pointer-to-pointer types; if you dereference a void ** pointer, it needs to be pointing at a genuine void * object1.
In this case, presuming that dequeue() is returning a single pointer value by storing it through the provided pointer, to be formally correct you would need to do:
int main( void )
{
void *p;
double *target;
success = dequeue(queueIn, &p);
target = p;
When you write it like this, the conversion from void * to double * is explicit, which allows the compiler to do any magic that's necessary (even though in the overwhelmingly common case, there's no magic at all).
1. ...or a char *, unsigned char * or signed char * object, because there's a special rule for those.

In your prototype declaration , you said second argument as void** ,so you have to type cast double** to void**.
Instead of this line success = dequeue(queueIn, &target);.
Call like this success = dequeue(queueIn,(void**) &target);

int main( void )
{
// Local Declaration
double *target;
// Statement
success = dequeue(queueIn, (void**)&target);
}
Use it like this.

Related

Auto cast of void* argument in function pointer

Following code works fine, however I was wondering if this is valid use of rule that void* is compatible with any other pointer
#include <stdio.h>
typedef struct {
int foo;
} SomeStruct_t;
typedef void(*SomeFunction_t)(void* ptr);
void bar(SomeStruct_t* str) {
printf("%d\n", str->foo);
}
void teddy(void* anyPtr) {
SomeStruct_t* str = (SomeStruct_t*)anyPtr;
printf("%d\n", str->foo);
}
int main()
{
SomeFunction_t functPtr = (SomeFunction_t)bar;
SomeStruct_t data = {.foo = 33};
functPtr(&data);
functPtr = teddy;
functPtr(&data);
return 0;
}
Question is, should I use bar or teddy variant? I prefer bar but I'm not sure if for some corner cases this might lead to hard to detect problem.
This is not valid:
SomeFunction_t functPtr = (SomeFunction_t)bar;
Because you're casing a function pointer of type void (*)(SomeStruct_t*) to type void (*)(void*) and subsequently calling it though the casted type. The function pointer types are not compatible because the parameters are not compatible. This triggers undefined behavior.
While a SomeStruct_t * can be converted to a void *, that conversion can't happen because the casted function pointer prevents it. There's no guarantee that SomeStruct_t * and void * have the same representation.
Using the function teddy which matches the function pointer type is safe. Also, you don't need to cast the parameter to SomeStruct_t * inside the function because conversions to/from void * don't require one in most cases.

double pointers error in C when compiling error when using void as well

I'm new to C and im currently learning about pointers.
I'm not sure why I am getting an error with the following sections of code in regards to pointers :
char ch;
char** pointer;
pointer = &ch;
and
int function1(void)
{
return 42.0;
}
void function2(void)
{
void (*pointer)(int);
pointer = &function1;
...
}
Any help will be appreciated :)
The very first problem is that you are using a double pointer in char** pointer ,as you are not storing the address of some other pointer so you should use char *pointer instead.
Then your function1 has return type as int but you are returning a float value ,although it won't give you any error but it can create some logical issues in your program,so better to properly write the return type in function definition and its prototype.
Then the next problem is in the function2,your function1 returns int but does not take any arguments but your function pointer return void and take int ,so you should better modify this to
int (*pointer)(void);
and then store the address of function1 in pointer ,it will work fine.
* is a single pointer and ** is a pointer to pointer.
So instead of
char** pointer;
It should be:
char* pointer;
In the second case, the function pointer prototype is not matching the prototype of the function it is pointing to.
So instead of
void (*pointer)(int);
it should be:
int (*pointer)(void);
you second section have some mistakes
you function1() return int and not take args
but your fucntion ptr return void and take int
so change it to:
int (*pointer)(void);
pointer = &function1;

Invalid type of arguments C

I am trying to implement a function that read lines from a file and put them into a string array. But it gives me the warning:
expected char ** But argument is of type char * (*)[(sizetype)(numberOfchar)]
It was working on Windows but when I switch into Linux it stops working.
Here is the caller and the array variable :
char *hashes[numberOfchar];
PutInArray(textName, numberOfchar, &hashes);
And here is the function (the void* is for the next part of the program, threading) :
void* PutInArray(char* k, int d, char *tab[d]) {
FILE* fp = NULL;
int i;
fp = fopen(k, "r");
if(fp != NULL) {
for (i = 0; i < d; i++) {
tab[i] = (char *)malloc((34) * sizeof(char));
fgets(tab[i], 34, fp);
}
fclose(fp);
}
}
Let's see how function calls work for other types.
You have a variable int v; and a function void foo(int x) (the variable declaration and the parameter declaration look the same). You call foo(v). You also have a function void bar(int* x) (the variable declaration has one star less than the parameter declaration). You call bar(&v).
You have a variable int* v; and a function void foo(int* x) (the variable declaration and the parameter declaration look the same). You call foo(v). You also have a function void bar(int** x) (the variable declaration has one star less than the parameter declaration). You call bar(&v).
You have a variable const struct moo ***v and a function void foo(const struct moo ***x) (the variable declaration and the parameter declaration look the same). You call foo(v). You also have a function void bar(const struct moo ****x) (the variable declaration has one star less than the parameter declaration). You call bar(&v).
You have a variable char *hashes[numberOfchar] and a function void* PutInArray(char* k, int d, char *tab[d]). The variable declaration and the parameter declaration still look the same. Why on God's green earth stick & in front of the variable?
I hear you saying "but I want to pass hashes by reference, and to pass by reference I need to use &". Nope, arrays are automatically passed by reference (or rather an array automatically gets converted to a pointer of its first element; parameters of array type are similarly adjusted so that the rule formulated above just works).
For completeness, the analogue of bar would have a parameter that looks like this:
char* (*tab)[numberOfchar]
and if you had such parameter, you would have to use &hashes. But you don't need it.
Your code is almost OK. Concerning the error/warning you get, just write PutInArray(textName, numberOfchar, hashes) instead of PutInArray(textName, numberOfchar, &hashes) for the following reason:
In function PutInArray(char* k, int d, char *tab[d]), char *tab[d] has the same meaning as char*[] and char**, i.e. it behaves as a pointer to a pointer to a char.
Then you define hashes as char *hashes[numberOfchar], which is an array of pointers to char. When using hashes as function argument, hashes decays to a pointer to the first entry of the array, i.e. to a value of type char **, which matches the type of argument tab. However, if you pass &hashes, then you'd pass a pointer to type char *[], which is one indirection to much. (BTW: passing &hashes[0] would be OK).
BTW: PutInChar should either return a value or should be declared as void PutInArray(char* k, int d, char *tab[d]) (not void*).

Double pointer conversions, passing into function with `const void **ptr` parameter

GCC gives me folowing warning:
note: expected 'const void **' but argument is of type 'const struct auth **
Is there any case, where it could cause problems?
Bigger snippet is
struct auth *current;
gl_list_iterator_next(&it, &current, NULL);
Function just stores in current some void * pointer.
The error message is clear enough: you are passing a struct auth ** where a void ** was accepted. There is no implicit conversion between these types as a void* may not have the same size and alignment as other pointer types.
The solution is to use an intermediate void*:
void *current_void;
struct auth *current;
gl_list_iterator_next(&it, &current_void, NULL);
current = current_void;
EDIT: to address the comments below, here's an example of why this is necessary. Suppose you're on a platform where sizeof(struct auth*) == sizeof(short) == 2, while sizeof(void*) == sizeof(long) == 4; that's allowed by the C standard and platforms with varying pointer sizes actually exist. Then the OP's code would be similar to doing
short current;
long *p = (long *)(&current); // cast added, similar to casting to void**
// now call a function that does writes to *p, as in
*p = 0xDEADBEEF; // undefined behavior!
However, this program too can be made to work by introducing an intermediate long (although the result may only be meaningful when the long's value is small enough to store in a short).
Hm... I think constructs like const void * doesn't makes much sense.
Because if user wants to access data under void * he needs casting from void, and this action bypasses compiler type checks and consequently - constantness.
Consider this example:
#include <stdio.h>
#include <stdlib.h>
int main () {
int i = 6;
int * pi = &i;
const void * pcv = pi;
const int * pci = pi;
// casting avoids type checker, so constantness is irrelevant here
*(int *)pcv = 7;
// here we don't need casting, and thus compiler is able to guard read-only data
*pci = 7;
return 0;
}
So conclusion is that we need either void pointer Or to ensure constantness of data, but not both.

How do I realloc an array of function pointers?

Straight to the code:
#define PRO_SIGNAL( func, param ) (*func)(param)
void PRO_SIGNAL( paint[0], Pro_Window* );
signal->paint = realloc( signal->paint, sizeof( void (*)(Pro_Window*) ) * signal->paint_count );
The Error:
error: incompatible types when assigning to type 'void (*[])(struct Pro_Window *)' from type 'void *'|
It appears that you are assigning to an array not a pointer.
From your output error message:
'void (*[])(struct Pro_Window *)' from type 'void *'|
Note the [] in there (and it certainly isn't a lambda!) rather than a *
If this is an "extendable" struct you need to realloc the entire struct not just the array member.
By the way, a tip: if realloc fails it returns a NULL pointer and if you assign it to the variable that was being realloc'ed, the original memory it was pointing to will be lost forever. So always realloc into a temp first, check the value, and then assign back to the original pointer if it worked.
You don't show us the definition of singal->paint, but I infer from the error message that it's declared as an array of function pointers, meaning signal is a struct with a flex array (paint[]). You can't assign to an array, you need to realloc the whole struct.
Not sure what you're trying to do, but this works perfectly here:
#include <stdlib.h>
int main(int argc, char ** argv)
{
void (**foobar) (int a, int b);
void (**tmp) (int a, int b);
foobar = NULL;
if (!(foobar = malloc(sizeof(*foobar)*4))
return 1;
if (!(tmp = realloc(foobar, sizeof(*foobar)*5)) {
free(foobar);
return 1;
} else {
foobar = tmp;
}
free(foobar);
return 0;
}
So, either you're trying to realloc an array like Kevin says, or perhaps you're compiling in C++ mode, where I believe that the cast is not implicit.
Edit: I've added some error handling.

Resources