Cast from (void**) to (int*) and viceversa - c

I did a function f which takes as input a (void*), convert it to a (int*) and print the value.
#include <stdlib.h>
#include <stdio.h>
void f(void* p)
{
int *pi = (int*)p;
printf("%d\n", *pi);
}
int main()
{
int x = 1;
int *px = &x;
void *pv = (void*)px;
f(pv);
return 0;
}
Is it possible to implement a function:
void f2(void** pp);
such that it performs the "same" operations of the function f? My goal is to learn how to convert a (int*) to a (void**) and viceversa.
EDIT: error and warning of #tadman code (I did a mistake)
fvv.c: In function ‘f2’:
fvv.c:10:12: warning: initialization of ‘int *’ from incompatible pointer type ‘int **’ [-Wincompatible-pointer-types]
10 | int *pi = (int**)p;
| ^
fvv.c:12:17: error: invalid type argument of unary ‘*’ (have ‘int’)
12 | printf("%d\n", **pi);
|
EDIT2
fvv.c: In function ‘main’:
fvv.c:19:5: warning: passing argument 1 of ‘f2’ from incompatible pointer type [-Wincompatible-pointer-types]
19 | f2(&px);
| ^~~
| |
| int **
fvv.c:7:16: note: expected ‘void **’ but argument is of type ‘int **’
7 | void f2(void** p)

You can take any level of indirection you want, up to the blatantly, utterly absurd (void*******), but I'm not sure why this would be useful:
void f2(void** p)
{
// Note you must maintain the same level of indirection
int **pi = (int**)p;
// Since this is a ** pointer, it requires ** to fully de-reference
printf("%d\n", **pi);
}
To call this you need a pointer to a pointer:
int x = 1;
int *px = &x;
f2((void**) &px);
In C terms a pointer to a pointer is often interpreted to mean one of the two following things:
A two dimensional array
A mutable pointer argument
Neither of those apply here.
That being said, in C there's not a lot of rules as to what you can and can't convert. If you want to do it, C isn't going to get in your way, even if the resulting code makes no sense or will crash immediately when executed.
You can convert int* to void** and back again, C won't care, but you should have a really good reason for doing such a thing. Normally arbitrary pointers are almost always specified as void*, and as this can be recast into whatever you want, it's sufficient.
For example, you can specify void* as an argument when that pointer is actually int**, something you'll see quite often, as in thread_create taking a void* arg argument. That's not limited to mere pointers, you can cast to your heart's content.

Related

My compiler returned "assignment to 'int *' from incompatible pointer type 'char *' [-Wincompatible-pointer-types]" when I ran my C program

#include <stdio.h>
int main()
{
char grade = 'A';
int *p = &grade;
printf("The address where the grade is stored: %p\n", p);
printf("Grade: %c\n", grade);
return 0;
}
I get this error each time I compile the code on VScode but never on code blocks.
warning: incompatible pointer types initializing 'int *' with an
expression of type 'char *' [-Wincompatible-pointer-types]
int *p = &grade;
^ ~~~~~~
1 warning generated.
 ./main
The address where the grade is stored: 0x7ffc3bb0ee2b
Grade: A"
The warning tells you exactly what it is. It says:
incompatible pointer types initializing 'int *' with an expression of type 'char *'
This means that p is of type int *, that &grade is of type char *, and that these two pointers are not compatible. The solution is to change the declaration of p to:
char *p = &grade;
One more thing. Usually you can safely do implicit conversions to and from any pointer to void *, but not when passed as argument to a variadic function. If you want to print the address, use this:
printf("%p", (void *)p);
But only cast when needed. Never do it just to get rid of warnings. Here is an answer I wrote about that: https://stackoverflow.com/a/62563330/6699433
As an alternative, you could use a void pointer directly:
void *p = &grade;
printf("%p", p);
But then you would need to cast if you want to dereference it. For example:
char c = *(char*)p;
That cast is not necessary if p is declared as char *.

correct return type for C function?

I am using an array of strings inside my function declared like this
char (*array)[PATH_MAX] = malloc (1000 * sizeof *array);
Allocating 1000 char pointers of size PATH_MAX (1024).
I want the function to return that specific data structure, i.e. return the pointer array. But I can't manage to choose the correct return type.
warning: returning 'char (*)[1024]' from a function with return type 'int' makes integer from pointer without a cast [-Wint-conversion]
I get that I can't have int as return type, but char** doesn't work either.
warning: returning 'char (*)[1024]' from a function with incompatible return type 'char **' [-Wincompatible-pointer-types]
I've tried using char (*)[1024] as return type, but it gives me generic C error messages, leading me to believe that I am not using the correct syntax.
error: expected identifier or '(' before ')' token
38 | char (*)[1024] read_dir (char *path) {
| ^
Is there a correct syntax for achieving this or am I just doing it wrong?
You need to define the function as follows:
char (*read_dir(char *path))[PATH_MAX] {
This specifies the return type as a pointer to an array of size PATH_MAX of char *.
Time for typedef
typedef char arr1k_char[1000];
arr1k_char *foo(int n) {
arr1k_char *x = malloc(n * sizeof *x);
return x;
}
https://ideone.com/Cqxa61

C - Trouble passing array reference to pointer argument in function

I'm having trouble passing an integer array as a reference, and then modifying the original array.
#include <stdio.h>
// sets the 2 element of i to 5
void setToFive(int *i[10]){
*i[2] = 5;
printf("hello\n");
}
int main(){
int i[10];
setToFive(&i);
// confirm i[2] == 5
printf("%d\n", i[2]);
}
Compiler complains about invalid type
[vinessa#komputilo ch1]$ gcc test.c
test.c: In function ‘setToFive’:
test.c:5:5: error: invalid type argument of unary ‘*’ (have ‘int’)
5 | *i[2] = 5;
| ^~~~~
test.c: In function ‘main’:
test.c:11:15: warning: passing argument 1 of ‘setToFive’ from incompatible pointer type [-Wincompatible-pointer-types]
11 | setToFive(&i);
| ^~
| |
| int (*)[10]
test.c:4:21: note: expected ‘int *’ but argument is of type ‘int (*)[10]’
4 | void setToFive(int *i){
| ~~~~~^
segmentation fault
[vinessa#komputilo ch1]$ ./a.out
Segmentation fault (core dumped)
Have been banging head at problem for hours, please help.
Here you are
#include <stdio.h>
// sets the 2 element of i to 5
void setToFive(int *i){
i[2] = 5;
printf("hello\n");
}
int main(){
int i[10];
setToFive(i);
printf("%d\n", i[2]);
}
If you want to change elements of an array then just pass it by value. In this case the array designator is implicitly converted to pointer to its first element. Using the pointer and the pointer arithmetic you can change any element of the array.
In fact in this case you are passing elements of the array by reference indirectly through a pointer to them.
Pay attention to that these function declarations
void setToFive(int i[100]);
void setToFive(int i[10]);
void setToFive(int i[1]);
void setToFive(int i[]);
are equivalent and declare the same one function declaration of which the compiler adjusts to the following declaration
void setToFive(int *i);
That is as a result the function deals with a pointer.
As for the expression used as an argument in this function call
setToFive(&i);
then it has the type int ( * )[10] because the pointed array is declared like
int i[10];
It is not the same as the type of the parameter int *i[10] that as I already wrote is adjusted by the compiler to the type int **.
You are passing an array of pointers to integers, not an array of integers. You can just remove the various * declarations and operators, and just pass a simple array as the argument (the array argument will decay to a pointer):
#include <stdio.h>
// sets the 2 element of i to 5
void setToFive(int i[10])
{
i[2] = 5;
printf("hello\n");
}
int main()
{
int i[10];
setToFive(i);
// confirm i[2] == 5
printf("%d\n", i[2]);
return 0;
}

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

warning: assignment makes pointer from integer without a cast error

I was doing this exercise and I had to write a program that takes in a list of numbers and swaps pairs of numbers so they're in order:
void swapPairs(int* a[], int length)
{
int i=0;
int temp;
while(i<(length-1))
{
if(a[i]>a[i+1])
{
temp=a[i];
a[i]=a[i+1];
a[i+1]=temp;
}
i++;
}
}
int main()
{
int array[]={2,1,3,1};
swapPairs(array, 4);
return 0;
}
I keep getting these errors:
In function ‘swapPairs’:
warning: assignment makes integer from pointer without a cast
temp=a[i];
^
warning: assignment makes pointer from integer without a cast
a[i+1]=temp;
In function ‘main’: warning: passing argument 1 of ‘swapPairs’ from incompatible pointer type
swapPairs(array, 4);
^
note: expected ‘int **’ but argument is of type ‘int *’
void swapPairs(int* a[], int length)
^
When I tried it with just an array instead of a pointer, it worked perfectly fine. Can someone please explain what is wrong with this and how to fix it?
Thanks in advance.
Your declaration of swapPairs is wrong - it shouldn't accept an array of int * (int pointers) - it should accept and an array of ints:
void swapPairs(int a[], int length)
The type of 'temp' is int. The type of 'a[i]' is *int (pointer to an int).
You are assigning the value of a pointer rather than the value of an integer because you are failing to dereference the pointer.
The while loop should read:
while(i<(length-1))
{
if(*(a[i])>*(a[i+1]))
{
temp=*(a[i]);
*(a[i])=*(a[i+1]);
*(a[i+1])=temp;
}
i++;
}

Resources