C Programming- Pointers - c

I came across the following code, the output for which is 0.
Is the statement vptr = &i correct? Can we assign a void pointer, address of an integer variable?
#include<stdio.h>
void fun(void *p);
int i;
int main()
{
void *vptr;
vptr = &i;
fun(vptr);
return 0;
}
void fun(void *p)
{
int **q;
q = (int**)&p;
printf("%d\n", **q);
}

The statement vptr = &i; is fine.
However, the statement q = (int**)&p; is incorrect. &p does not point at an int*, it points at a void*. It is not guaranteed that int* and void* have compatible layouts.
A correct implementation of fun would be
void fun(void *p)
{
printf("%d\n", *(int*)p);
}

Any pointer type can be converted into void*.
From the C standard 6.3.2.3p1:
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.

Related

why trying to deference void pointer does not work?

int main()
{
int b = 12;
void *ptr = &b;
printf("%d", *ptr);
return 0;
}
I expected for this code to print 12, but it does not.
if instead of void pointer, we define int pointer it would work.
I wanted to know how can we use void pointer and print the address allocated to it and the amount saved in it?
Dereferencing a void * doesn't make sense because it has no way of knowing the type of the memory it points to.
You would need to cast to pointer to a int * and then dereference it.
printf("%d", *((int *)ptr));
void pointers cannot be dereferenced.it will give this warning
Compiler Error: 'void' is not a pointer-to-object type*
so, you have to do it like this.
#include<stdio.h>
int main()
{
int b = 12;
void *ptr = &b;
printf("%d", *(int *)ptr);
return 0;
}
If p has type void *, then the expression *p has type void, which means "no value". You can't pass a void expression to printf for the %d conversion specifier (or any other conversion specifier).
In order to dereference a void *, you must first convert it to a pointer of the appropriate type. You can do it with a cast:
printf( "%d\n", *(int *) ptr );
or assign it to a pointer of the appropriate type:
int *p = ptr;
printf( "%d\n", *p );
The rules around void pointers are special such that they can be assigned to other pointer types without an explicit cast - this allows them to be used as a "generic" pointer type. However, you cannot directly examine the thing a void pointer points to.
A schoolbook example of when void pointers are useful is qsort.
This is the signature:
void qsort(void *base,
size_t nitems,
size_t size,
int (*compar)(const void *, const void*)
);
base is just a pointer to the first element. The reason it's a void pointer is because qsort can be used for any list, regardless of type. nitems is number of items (doh) in the list, and size is the size of each element. Nothing strange so far.
But it does also take a fourth argument, which is a function pointer. You're supposed to write a custom compare function and pass a pointer to this function. This is what makes qsort able to sort any list. But since it's supposed to be generic, it takes two void pointers as argument. Here is an example of such a compare function, which is a bit bloated for clarity:
int cmpfloat(const void *a, const void *b) {
const float *aa = (float*) a;
const float *bb = (float*) b;
if(*aa == *bb) {
return 0;
} else if(*aa > *bb) {
return 1;
} else {
return -1;
}
}
Pretty clear what is going on. It returns positive number if a>b, zero if they are equal and negative if b>a, which is the requirements. In reality, I'd just write it like this:
int cmpfloat(const void *a, const void *b) {
return *(float*)a - *(float*)b;
}
What you do with this is something like:
float arr[5] = {5.1, 3.4, 8.9, 3.4, 1.3};
qsort(arr, 5, sizeof *arr, cmpfloat);
Maybe it's not completely accurate to say that void pointers are used instead of templates, generic functions, overloaded functions and such, but they have similarities.

I want to know how to pass the address of an integer pointer and modify it by dereferencing,

I want to know how we could pass the address of a pointer and in the function call, we change its value by dereferencing.
int main(){
int x=7;
int *p; // pointer to integer
p=&x;
modify(&p); //passing address of pointer to integer
}
For the function below, do we need one asterisk or two? and how to dereference is_
void modify(int *p){
}
void modify(int **p)
{
**p = 50;
}
The variable p in main has type int *, so it's adddress has type int **. That should be the type of the parameter to modify.
Then, assuming you want to modify x, you need to dereference the parameter p in modify twice:
void modify(int **p){
**p = 50;
}

Converting a int pointer to a void pointer and back to use the value in another function?

I would like to convert a int pointer to a void pointer and pass that void pointer to a function and then back to an int pointer to use that value in another function.
void main(){
int newSize = size;
void *newSizePtr = &newSize;
someFunc(newSizePtr);
}
void someFunc(void *newSizePtr){
int actualValue = *((int *) newSizePtr);
}
Is this the right way to convert a int ptr to a void ptr and then back to use the value?
i am unable to dynamically allocate memory to the pointer itself because of restrictions with my program that i cannot use malloc. i.e.
int *newSize = malloc(sizeof(int));
which is why i did it this way.
i also need to pass in a void* argument because in my program i am using pthread_create(). This function requires me to pass in an argument of a void* to the function which is why i casted it to a void* and then back when i needed to use it
The conversion you are doing is explicitly allowed by the C standard. Section 6.3.2.3p1 regarding pointer conversions states:
A pointer to void may be converted to or from a pointer to any
object type. A pointer toa ny object type may be converted to a
pointer to void and back again; the result shall compare equal
to the original pointer.
It's also not necessary to explictily cast to or from a void *. So you can do something like this:
void someFunc(void *newSizePtr){
int *actualValuePtr = newSizePtr;
}
int main(){
int newSize = size;
pthread_t tid;
pthread_create(&tid, NULL, someFunc, &newSize);
}
#include <stdio.h>
#include <memory>
void someFunc(void*);
int main() {
int size = 4;
int newSize = size;
void* newSizePtr = &newSize;
someFunc(newSizePtr);
// void* -> int*, before using
int* newSize = (int*) malloc(sizeof(int));
}
void someFunc(void* newSizePtr) {
int actualValue = *((int*)newSizePtr);
printf("%d", actualValue);
}
Yes you can cast void* to int*, and int* to void *,
Because, void * is 'generic' pointer.
malloc returns generic pointer (void*) because malloc does not know what 'type' of return you need.
So, you need to convert to the type you need.
(In the above code, you need to convert to void* -> int*)
For more information about usage of generic pointer, below link may help you
https://codexpart.com/what-is-generic-pointer-difference-between-generic-pointer-and-void-pointer/

what this (int**)&p; mean in the statement?

This code is practice code for pointers. But I am not understanding the (int**)&p; means in this code.
void fun(void *p);
int i;
int main()
{
void *vptr;
vptr = &i;
fun(vptr);
return 0;
}
void fun(void *p)
{
int **q;
q = (int**)&p;
printf("%d\n", **q);
}
Please elaborate how it is evaluated.
It's a type cast, that interprets the value of &p, which has type void **, as instead having type int ** which is the type of the variable the value is stored in.
The cast is necessary, since void ** is not the same as void * and does not automatically convert to/from other (data) pointer types. This can be confusing.
&p being of type void**, is being casted to type of int** which is to be assigned to q.
SIDE-NOTE : "Any pointer can be assigned to a pointer to void. It can then be cast back to its original
pointer type. When this happens the value will be equal to the original pointer value."
Be careful when using pointers to void. If you cast an arbitrary
pointer to a pointer to void, there is nothing preventing you from
casting it to a different pointer type.

Error: Invalid use of void pointer

Reading about void pointers:-
When we assign address of integer to the void pointer, pointer will become Integer Pointer.
When we assign address of Character Data type to void pointer it will become Character Pointer.
And the code:
void main()
{
float f = 111.35;
void * fp;
fp = &f;
printf("%.2f\n",*fp);
}
It shows the error follows :Invalid use of void pointer
If I change the type of the pointer to a float * fp, there is no error.
The type of a void pointer is "pointer to void" and nothing else. And since void doesn't have a type you have to explicit cast it to the correct type when dereferencing it, like
*(float *) fp;
Your variable type must be specified before printf or in the printf, thus you can not access a void * variable before you cast it to a right type of c.
The prime benefit of using void pointer is its reusability.
You can use fp to point to a char* or int* or float* in successive statements.
When you state vp =&f, it implies that vp can act as a float pointer.
It does not become a float pointer.
So when you dereference it ( as in printf), you need to typecast it.
int main()
{
int iVal = 9;
float fVal = 9.0;
void *ptr;
ptr = &iVal;
printf("iVal = %d\n",*((int*)ptr)); //De-referencing
//Resuability
ptr = &fVal;
printf("fVal = %f\n",*((float*)ptr)); //De-referencing
return(0);
}

Resources