What is meant by void *p = &i ? - c

In below code, how can void pointer p store address of i? What is the meaning of "*(float *)p" inside printf() ?
#include
void main()
{
int i = 10;
void *p = &i;
printf("%f\n", *(float *)p);
}

A void* can store any address. It's a "generalized pointer" basically. You can cast back the void* to the type you saved into it to get a useful type out of it and do things with it like pointer arithmetic or dereferencing the pointer. The pointer itself doesn't know anything about what type it stores and thus you have to tell it what type it's pointing to so. It's lack of type makes it dangerous since it's the programmer's job to remember what type the pointer points to.
In your case, you make p point to the address of i which is an int and then you try to print out the pointee of p as a float while you didn't assign it to the address of a float in the first place. This is undefined behaviour and a good example of the dangers of a void* in inexperienced hands.

In C void* can point to any type of memory location. You can assign void* to a variable of type int*, double*, char*.., etc. Generally void* is used to pass parameters to the function who type is not know at the time of defining.
But You can have any variable of type void. So at the time of dereferencing you have to cast a void* to some pointer type but not void*.
so by *(float *)p (which is undefined) you are casting p(which is void* type) to float* type, then you are dereferencing it to double(But memory is actually int). So that it expects float type variable at the memory it is pointing to.

how can void pointer p store address of i?
A void pointer can point to any data pointer. See C11 draft, 6.3.2.3. So,
void *p = &i;
simply makes p point to the address of object i.
You can later safely convert it back to an int*. For example,
int i = 10;
void *p = &i;
int *j = p; /* j now point to &i */
or you can directly cast p and use it:
printf("%d\n", *((int*) p));
This is all fine.
What is the meaning of "*(float *)p" inside printf() ?
It's an attempt to reinterpret an int object as a float object which isn't allowed. In this statement:
printf("%f\n", *(float *)p);
You are casting p, a void*, to a float* which may be undefined because the object p points to is an int and you are attempting to
reinterpret it as if it's a float object. From C11 draft, 6.3.2.3:
A pointer to an object type may be converted to a pointer to a
different object type. If the resulting pointer is not correctly
aligned68) for the referenced type, the behavior is undefined.
Otherwise, when converted back again, the result shall compare equal
to the original pointer. When a pointer to an object is converted to a
pointer to a character type, the result points to the lowest addressed
byte of the object. Successive increments of the result, up to the
size of the object, yield pointers to the remaining bytes of the
object.
This also violates C11 draft, 6.5.7 as int* and float* are distinct types and are not compatible with each other.

Related

Type of address and pointers in c

I have 2 questions about pointers in c.
1) from my understanding the & returns the memory address of a variable. For example:
int x=10;
int *p=&x;
So I think that the & will return the memory address of x and that memory address is type int* because the variable type of x is int.
Also because the type of the address is int* I believe that is the reason that only an int* (and void *) pointer can point in the address (they are the same type).
Any thoughts about that? comments? I don't know if I am correct.
2) It's about the void pointer. I know that the void* pointer can point to any type of variable. For example
int x=10;
void *ptr=&x;
Now I have a function:
void * foo(some parameters)
{
// just for this example let's say that I return the address of a local variable
// I know that is wrong to do so because when the foo ends
// the local variables deallocate
int k=10;
void *ptr=&k;
return ptr;
}
So my pointer is type void but it points to int* memory address. So ptr will save the address of k and when I return ptr the address of k is returned which is type int* . But my function is type void*.
What is happening here?
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 for example in this code snippet
int x = 10;
void *p = &x;
the expression &x in the right side of the assignment has the type int *. According to the quote it may be converted to pointer of the type void * in the left side of the assignment.
1) Yes all of that is correct.
2) The type of the pointed-at data remains int no matter what kind of pointer that points at it. (This is known as effective type in formal C.) In your example you return a void pointer so that's the type the caller gets. The information of what type it pointed at is lost, from the point you do void *ptr=&k; and onward. This is why void pointers are problematic to use.
1) You are correct
2) It is simply returning a void * that is pointing to k - a local variable. (Any pointers can be cast to void pointers).
You are correct in saying that you should not use the returned value as k no longer exists

Why use a void pointer for dereferencing variables of datatypes?

Dereferencing a float variable using a void pointer:
#include <stdio.h>
int main() {
float a = 7.5;
void *vp = &a;
printf("%f", *(float*)vp); /* Typecasting a void pointer to float for dereference */
printf("\n");
}
Output: 7.500000
Dereferencing a variable using an integer pointer:
#include <stdio.h>
int main() {
float a = 7.5;
int *ip = &a;
printf("%f", *(float*)ip); /* Typecasting an int pointer to float for dereference */
printf("\n");
}
Output: 7.500000
In both, the outputs are same. What is the reason to go for dereferencing of different datatype variable, when we are able to do by typecasting a normal pointer?
Converting any data pointer to void* pointer and back is guaranteed to give back original pointer.
From C11 standard draft N1570:
6.3.2.3 Pointers
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.
Converting data pointer to other data pointer than void* (int* in your example) may work. It depends on the compiler you are using and the system you are on. Not all systems might use same internal representation for different pointer types.
A pointer to an object type may be converted to a pointer to a different object type. If the
resulting pointer is not correctly aligned 68) for the referenced type, the behavior is
undefined. Otherwise, when converted back again, the result shall compare equal to the
original pointer. When a pointer to an object is converted to a pointer to a character type,
the result points to the lowest addressed byte of the object. Successive increments of the
result, up to the size of the object, yield pointers to the remaining bytes of the object.
This is different from strict aliasing rules.
float a = 7.5;
int *ip=&a;
int i = *ip; // Dereferenced using invalid type
Code above breaks strict aliasing rule as dereferenced type is not the same as the original type. This results in undefined behaviour and is always invalid code.
A void pointer is a generic pointer which can hold the address of any type and can be typecast to any type.
In the first case, the program successfully compiled and ran without any warning or error, because using a void pointer to convert from one pointer type to another and then storing or casting it to the final type is safe without losing data.
But in the second case the GCC compiler generated a warning
prog.c: In function 'main':
prog.c:5:9: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
int *ip=&a;
^
clang compiler:
warning: incompatible pointer types initializing 'int *' with an expression of type 'float *' [-Wincompatible-pointer-types]
int *ip=&a;
^ ~~
The C11 Standard, 6.3.2.3, paragraph 7:
A pointer to an object or incomplete type may be converted to a
pointer to a different object or incomplete type. If the resulting
pointer is not correctly aligned for the referenced type, the behavior
is undefined.
A void pointer is (sort of) untyped. It can point to anything without the compiler complaining. e.g. If you have an int variable, you can safely create a void pointer that points to this and pass it around. e.g.
int x = 10;
void *p = &x
is fine but
int x = 10;
float *p = &x;
will upset the compiler
This is especially useful for functions that operate on multiple pointer types or if you will decide what something is at runtime.
However, void pointers cannot be dereferenced (*) directly because the compiler doesn't know their type. So,
printf("%d\n", *p);
will break if p is void pointer. We have to know the size of what it points to to dereference it and this is done using a manual type cast (like what you've done).
In your specific case, you have a pointer that points to a float which you type cast back into float before printing it. So, you will get the same output. The void * pointer is not really playing a big role here.
An example of where you need a void * is the malloc function, If you look at the prototype, it returns a void *. i.e. a block of raw memory. You need to typecast this as a concrete type before you can do pointer arithmetic and dereferencing.

What exactly does void * mean

I have seen void * explained as a pointer to an unused chunk of memory. I have also seen void * described as a pointer to any type, or a pointer to any type can be cast to void *.
From what I know, int * means a pointer to type int. So keeping this in mind, what does void * mean literally? Is it a pointer to type void? This doesn't seem right because I did not know that void could be a type.
void * is a pointer to void.
C11: 6.3.2.3 Pointers:
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.
The compiler will not let you dereference a void* pointer because it does not know the size of the object pointed to but you need to cast void * type pointer to the right type before you dereference it.
Let's begin with this example:
int a = 65;
int *q = &a;
void *p = q;
char *c = p;
(source: qiniudn.com)
we define an int variable a, and an int pointer q pointing to it. p in the void * pointer.
The beginning address of a is 0x8400(just for simplicity).
A pointer is an address, no more.
No matter what type of pointer, they have the same memory size, and their value is an address.
So,
printf("%p, %p", *p, *q);
will display:
0x8400, 0x8400
Type: how you interpret the date
As you see in the graph, the data in memory is 65000000(this is little endian). If we want to use it, we have to specify what it is! And type does that.
printf("%d %c", *p, *q);
If we print it as integer, we get 65. If we print them as char, we get A(asciicode).
And p + 1 pointer to 0x8401, q + 1 points to 0x8404.
void *: a universal type
According to wikipedia:
A program can probably convert a pointer to any type of data (except a function pointer) to a pointer to void and back to the original type without losing information, which makes these pointers useful for polymorphic functions.
Yes, void * define a trivial unit of pointer, it can be converted to any pointer and vise versa. But you can't dereference it, because it doesn't specify a type.
If you want to manipulator on bytes, you should always use void *.
Isn't char * the same as void *
Not exactly.
The C language standard does not explicitly guarantee that the different pointer types have the same size.
You can't always hope char * have the same size on different platforms.
And converting char * to int * can be confusing, and mistakes can be made.
It means: a pointer to some memory, but this pointer does not contain any information about the type of data that may be stored in that memory.
This is why it's not possible to dereference a void *: the operation of dereferencing (and obtaining an rvalue, or writing through an lvalue) requires that the bits in the memory location be interpreted as a particular type, but we don't know which type to interpret the memory as.
The onus is on the programmer to make sure that data read in matches the type of data read out. The programmer might help himself in this by converting the void * to a pointer to an object type.
It's useful if you want to have a common interface for dealing with memory of multiple possible types, without requiring the user to do a lot of casting. for example free() takes a void * because the type information isn't necessary when doing the free operation.
void * is a pointer to data of unspecified type. As such, it can't be used directly; it must be cast to a usable datatype before it can be dereferenced.

Different ways to assign pointer in C , using & or *?

In C , if i want a pointer reference to a variable
int c = 12 ;
int *p ;
p = &c ;
or i can do it this way
int c = 12;
int p;
p=&c;
in both case value of p is the address of c , can you please tell the problems i will be facing .
You cannot do it this way:
int c = 12;
int p;
p = &c;
This is not valid C to assign a pointer value to an integer object. Enable all your compiler warnings, the compiler has to give a diagnostic message for the invalid assignment.
In the first case, there is no problem as p is a special type of variable which can contain address. Thus here p is called a pointer variable.
In second case, p is normal scalar variable which cannot contain address. So there is a problem. Compiler implicitly will not be able to assign the address of c variable to the variable p
& and * mean different things in different contexts.
& in a variable declaration (including in a function parameter) means "reference" or "by reference" in C++, and is not allowed in C. In C++, the type of j below is "int". It doesn't modify the type, but says "this is another name for existing data" rather than "create a space for new data".
int i = 5;
int &j = i; //C++ only: j is another name for i
int f(int & x); //f is a function that takes in an int by reference
* in a variable declaration means "pointer". The type of int* is "pointer to an int", while, again, the type of int& (C++ only) is int. It modifies the type.
int *p = NULL; //p is a pointer to an int, that currently points to nothing.
int f(int & x); //f is a function that takes in an int by reference
& in front of an existing variable means "a pointer to", or "address of". It's an operator, which can be thought of as a special kind of function. It takes in anything and returns a pointer to that thing.
int i = 5;
int *p = &i; //p points to i
int **pp = &p; //pp points to p
* in front of an existing variable means "what this is pointing to", also known as the dereference operator. Like &, it's an operator. It can only be applied to a pointer, and it returns what the pointer is pointing to.
int i = 5;
int *p = &i; //p points to i
int j = *p; //j copies what p is pointing to
So if I say *&var, that is the same as var, because it means "dereference the pointer to var".
int c = 12; int p; p=&c;
introduces the risk of losing bits from the address of c.
If you really need to store an address as integer then use uintptr_t as target integer type, as it's guaranteed by the C standard to be wide enough to store an address:
int c = 12; uintptr_t p; p = (void*)&c;
uintptr_t comes in <stdint.h>.
7.18.1.4 Integer types capable of holding object pointers
1
The following type designates a signed integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void,
and the result will compare equal to the original pointer:
intptr_t
The following type designates an unsigned integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void,
and the result will compare equal to the original pointer:
uintptr_t
These types are optional.
However to have this integer converted back to a pointer to an integer it casting needs to go via (void*):
int * pi = (void*)p;

can a void pointer safely point to annother pointer?

This might be obvious but, can a void pointer safely point to another pointer? i.e. point to a type int *
int i = 5;
int *ip = &i;
void *vp = &ip;
int *nip = *(int **)vp;
int ni = *nip; // == 5?
EDIT: Sorry maybe I'm not being clear, I would like to know if a void pointer can POINT TO a section of memory that has the type of another pointer; without being a void **. just void *
Yes, you can convert any object pointer to void * and back to the original pointer type without loss of information.
From the horse's mouth:
(C99, 6.3.2.3p1) "A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer."
Yes, it can point to any object type1. You can't actually dereference a void pointer since the compiler doesn't know the "real" type behind it. But the pointing aspect is fine.
From C11 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.
1/ "Object type" does not include functions, the rules for converting function pointers are slightly more restrictive.

Resources