Incompatible pointer types (double pointers) - c

In a function that asks a double pointer like this one:
#include <stdlib.h>
void prueba(void **ap)
{
*ap = NULL;
}
compiled with the following main:
#include <stdlib.h>
#include <stdio.h>
void prueba(void **ap);
int main(void)
{
char *str;
str = (char *)malloc(sizeof(char) * 5);
prueba(&str);
if (str == NULL)
printf("NULL");
return (0);
}
I get this warning with gcc:
main2.c:11:9: warning: incompatible pointer types passing 'char **' to parameter of type 'void **' [-Wincompatible-pointer-types]
prueba(&str);
^~~~
main2.c:4:23: note: passing argument to parameter 'ap' here
void prueba(void **ap);
But if i do the same but with simple pointers, that is give a pointer to char to a function who asks for a void pointer, gcc compiles without warnings, for example, the following compiles right:
function:
#include <stdlib.h>
void prueba(void *ap)
{
ap = NULL;
}
main:
#include <stdlib.h>
#include <stdio.h>
void prueba(void *ap);
int main(void)
{
char *str;
str = (char *)malloc(sizeof(char) * 5);
prueba(str);
if (str == NULL)
printf("NULL");
return (0);
}
So my question is, why it works with simple pointers but it does not work with double pointers (or greater i guess)?

According to the C Standard (6.3.2.3 Pointers)
1 A pointer to void may be converted to or from a pointer to any
object type. A pointer to any object type may be converted to a
pointer to void and back again; the result shall compare equal to the
original pointer.
So in the second code snippet a pointer of the type char * is implicitly converted to the type void * though the function does not make sense because it deals with a copy of its argument and therefore does not changes the original pointer.
However the type void ** is not the same as the type void *. So the quote is not applicable for the type void ** and the compiler issues a diagnostic message because there is no implicit conversion from a pointer to any object type to a pointer of the type void **.

A void * can freely be assigned to or from any object pointer freely. This freedom does not extends to void **, as that is a distinct type.
Also, your fixed program won't work as expected, since ap = NULL; only changes the local variable inside of prueba and not the parameter passed in.
Change your original program to accept a char ** instead of a void **.

Related

Why is there a warning for casting from char** to void**, but not from char* to void*?

I am quite new to C, and have been practicing with pointers. I understand that a void * pointer accepts a pointer of any kind, so this works fine:
void functionWithSingleVoidPointer(void *simplePointer)
{
free(simplePointer);
}
int main()
{
char *simplePointer = malloc(sizeof *simplePointer);
functionWithSingleVoidPointer(simplePointer); //No warnings
return 0;
}
However, I don't understand why this:
void functionWithDoubleVoidPointer(void **doublePointer)
{
free(*doublePointer);
}
int main()
{
char *simplePointer = malloc(sizeof *simplePointer);
char **doublePointer = &simplePointer;
functionWithDoubleVoidPointer(doublePointer);
}
gives me a warning:
warning: passing argument 1 of ‘functionWithDoubleVoidPointer’ from incompatible pointer type [-Wincompatible-pointer-types] ... note: expected ‘void **’ but argument is of type ‘char **’
Why doesn't the casting from char * to void * give any warning, but the casting from char ** to void ** does?
A char* value points to a char object; a void* object can point to any kind of object. The conversion is safe (as long you don't do anything unsafe with the result).
A char** pointer value must point to a pointer object of type char* somewhere in memory. A void** pointer value must point to an object of type void*. Since char* and void* are different types, you can't just assume that you can safely treat an object of one type as if it were an object of the other type. (Most likely they have the same representation, but the language doesn't guarantee that.)
A void** is not a void pointer, that's it.
void** is a pointer to a void pointer, which only accept void pointers.

Incompatible pointer type during function call

I have reduced my code to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void change_data (char *data);
int main (int argc, char *argv[])
{
char data[20] = {0};
strcpy(data, "This is a test.");
change_data(&data);
exit(EXIT_SUCCESS);
}
void change_data (char *data)
{
printf("%s\n", data);
}
I want to be able to change the main variable in the function. I thought that using & means sending the address rather than copying the data. But I get the following error when I compile:
tt.c: In function 'main':
tt.c:13:14: warning: passing argument 1 of 'change_data' from incompatible pointer type [-Wincompatible-pointer-types]
change_data(&data);
^
tt.c:5:6: note: expected 'char *' but argument is of type 'char (*)[20]'
void change_data (char *data);
^~~~~~~~~~~
Can someone show me what I'm doing wrong, because I don't have a clue. Ty.
Remove the &. data has type char[20], so a pointer to it has type char (*)[20]. An array will decay to a pointer type when it needs to do so, so simply passing data will pass it as char*.

Explain difference between the use of void pointer

My code needs to pass an array to a void pointer (The struct has (void *) that cannot be modified). The two versions of code below produce the same output but the latter has two warnings. My question is which of the two methods is preferred? Is there a way to typecast to remove the warnings?
This version does not have warnings and produces the output as expected:
#include <stdio.h>
void test(void *var_arr, char var_1);
typedef struct {
char chip;
void *buffer;
}test_struct;
int main()
{
int test_array[3] = {3,7,5};
char var_1 = 0x20;
printf("Hello, World!\n");
test(&test_array, var_1);
return 0;
}
void test(void *var_arr, char var_1)
{
int i;
test_struct var_ts;
var_ts.chip = var_1;
var_ts.buffer = var_arr;
for (i=0; i<3; ++i)
printf("\nThe data values are : %X \n\r", *((int *)var_ts.buffer+i));
}
Hello, World!
The data values are : 3
The data values are : 7
The data values are : 5
This version below has two warnings but compiles and produces the output expected:
Warning(s):
source_file.c: In function ‘main’:
source_file.c:17:10: warning: passing argument 1 of ‘test’ from incompatible pointer type
test(&test_array, var_1);
^
source_file.c:3:6: note: expected ‘int ’ but argument is of type ‘int ()[3]’
void test(int *var_arr, char var_1);
#include <stdio.h>
void test(int *var_arr, char var_1);
typedef struct {
char chip;
void *buffer;
}test_struct;
int main()
{
int test_array[3] = {3,7,5};
char var_1 = 0x20;
printf("Hello, World!\n");
test(&test_array, var_1);
return 0;
}
void test(int *var_arr, char var_1)
{
int i;
test_struct var_ts;
var_ts.chip = var_1;
var_ts.buffer = (void *)var_arr;
for (i=0; i<3; ++i)
printf("\nThe data values are : %X \n\r", *((int *)var_ts.buffer+i));
}
The lower version tells you what the problem was in the first one: passing a pointer to the array instead of a pointer to the first element.
Passing a pointer to the array, which has the type int(*)[3]:
test(&test_array, var_1);
Passing a pointer to the first element, which has the type int*:
test(test_array, var_1);
The code happens to work because the two pointers points to the same address, so the pointer to the array appears to work, but the code is still undefined.
Passing a pointer to the first element is correct, as the array test_array, which has the type int[3] decays to type int* when it is passed to the function.
The warnings are shown because the compiler does static analysis on the code and identified a possible cause of bugs.
When using the void pointer the compiler cannot do this static analysis since it does not know what type is used.
If the datatype is known I would always prefer using this type as pointer instead of the void pointer. I would only use the void pointer when it is acceptable that the pointer can point to anything. In the end this is about personal taste and the code guidelines you follow.

Void** as parameter requires cast

I have a function in C that needs to receive a pointer to an array (with an unspecified type).
To do so, I use void**, as I would use void* to receive an array of unspecified elements.
There's a problem unfortunately: the compiler gives a warning (passing argument 1 of 'f' from incompatible pointer type). If I ignore the warning, and try to execute the program, everything works as expected.
The only way to get rid of the warning is to cast whatever I try to pass to the function to void**.
Why does C behaves like that? And is there a better way to solve the warning?
PS: I need to compile using GCC with the flags -std=gnu89 -pedantic -Wall
Example
int f(void** param){ return 1; }
int main(){
int *arr = malloc(sizeof(int) * 20);
int i;
for(i=0; i < 20; i++) arr[i] = i;
f(&arr);
}
The pointer to anything type is void*, and the compiler will not complain about conversions to that type. But void** is not a pointer to anything, it's a pointer to an array of pointers to anything, which is quite different from a pointer to an array of pointers to integers, so the compiler complains.
So, to solve the warning, yes you would need to cast explicitly.
Although void * is the "generic pointer" in C, void ** isn't a "generic pointer to pointer". Instead, it's nothing more than the "specific pointer to void *, the generic pointer".
In your case, a int ** is converted implicitly to a void **, which is not generic. Since a void ** is not guaranteed to be able to hold all pointer variables (thus incompatible to a int **), the compiler raises a warning.
Here is the warning generated by clang:
main.c:7:7: warning: incompatible pointer types passing 'int **' to parameter of
type 'void **' [-Wincompatible-pointer-types]
f(&arr);
^~~~
main.c:1:14: note: passing argument to parameter 'param' here
int f(void** param){ return 1; }
To eliminate this warning, you can have int f(void* param);, and cast param to int ** inside the function. There will be no warning because a void * can be used to store any pointer (Quoted from N1570):
6.3.2.3 Pointers
1 A pointer to void may be converted to or from a pointer to any
object type. A pointer to any object type may be converted to a
pointer to void and back again; the result shall compare equal to the
original pointer.
It seems that you want to modify the address of the data (not the value) inside the function, you can't do that directly with a void * because you can't use arithmetic with void *, but you can pass the size of the first element and a chunk of bytes (char *), suppose you want to change the address of arr to arr + 1 (the second element of the array) inside the function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void f(void *ptr, size_t size)
{
// char *p = *ptr; Wrong, you can't dereference a void * without a cast
char *p = *(char **)ptr; /* pointer to address of ptr */
memmove(p, p + size, size); /* assign the address of ptr + 1 to ptr */
}
int main(void)
{
int *arr = malloc(sizeof(int) * 20);
int i;
for (i = 0; i < 20; i++) arr[i] = i;
f(&arr, sizeof arr[0]);
printf("%d\n", arr[0]);
return 0;
}
Output:
1

output of the function with the float pointer parameter and input as a address of int variable

I am very new to this topic pointers in C. I have one code as follow.
The output of this code is 0.000000 but i can't understand why so?
void foo(float *);
int main()
{
int i=10,*p=&i;
foo(&i);
}
void foo(float *p)
{
printf("%f",*p);
First check this site to know pointer behavior.
In your code you declare float type parameter but pass integer value.
Try this one:
#include <stdio.h>
void foo(int *p)
{
printf("%d",*p);
}
int main()
{
int i=10,*p=&i;
foo(&i);
return 0;
}
It gives The below warning.
test.c:6:2: warning: passing argument 1 of ‘foo’ from incompatible pointer type [enabled by default]
Because, you are passing the address to the foo function but expected argument is float *.
Then you are defining the p pointer as a integer type.
The variable p does not points the i.
But in foo function calling, there is no address is passed.
So, It gives warning and 0.0000.
So, change your code like below.
void foo(float *);
int main()
{
flat i=10,*p=&i; //Change the data type
foo(&i);
}
void foo(float *p)
{
printf("%f",*p);
}
Now the output is
10.0000

Resources