I missed a couple classes, and don't really understand the flowing lecture slide's examples about the void pointer.
In the line "no,no,no", why we cannot deference P since P has been assigned a real pointer type q?
In the line " ?? ", is it legal to cast a pointer to a integer? ( I think it can compile because C doesn't check cast, but don't know what kind of result it is going to get
in this example
Conversion of integer pointer to integer
he casted *p = 10;
a = (int)p;
and someone answered that a is going to be a very large value.
but in my case,is (int) *p... Is it the same case as the example that I gave above?
The void pointer in C is a pointer that is not associated with any data types. It points to some data location in the storage. This means it points to the address of variables. It is also called the general purpose pointer.
void* is a pointer (or a pointer to the beginning of a unknown type array). void* is a pointer to the address of a pointer (or a pointer to the beginning of a 2D array).
"void*" means "this value is a pointer to something, but I'm not telling you what it points to". Start with this statement, and everything makes sense.
So it should be clear that you can't dereference a void*, because nobody told you what it points to! If you don't know whether it points to an int, a char, or some struct, what do you think should happen if you dereference it?
In C, you can assign a void* to any pointer, for example to an int*. The compiler doesn't know what the void* points to, but when you write r = p; the compiler says "I hope you know what you are doing, I trust you. " (A C++ compiler in the same situation doesn't trust you). If the void* p did indeed point to an int, everything is fine. Otherwise, things are more or less bad.
The ?? one is wrong. You can't dereference *p. Doesn't matter what you do afterwards, *p isn't allowed. And no pointer is cast to an integer. There is an attempt to dereference a pointer, which isn't allowed. The result of the dereference couldn't be anything useful since you don't know what p points to, so you have nothing useful to cast to an int.
Now what happens in * (int *) p: p is a void * - a pointer to something, but you don't know what it points to. (int * )p is a cast: p is converted to an int*. That means the compiler will believe that (int*)p points to an int - that may or may not be true. * (int * ) p dereferences the int*: So in total, you convinced the compiler that p points to an int, and to read the int that p hopefully points to. If p did actually point to an int, it's fine. If p didn't point to an int, you're in trouble.
Void pointers are specifically pointers that do not have a data type associated with them. You have to recast them to a specific type (I.e: int*) to have the ability to access their contents.
To clarify your specific points:
1) While p may have a pointer address, it does not have a specific data type associated to it (The data type is necessary for accessing the contents)
2) The result of this action is probably deterministic on the contents. I wouldn't recommend this as a good practice.
3) This is telling the compiler to treat the void pointer as an integer pointer. Therefore, it "knows" the data type associated with it, and accesses it as an int.
In the line "no,no,no", why we cannot deference P since P has been assigned a real pointer type q?
int a =2, *q = a, *r; //line 1
void *p; //line 2
p = q; // line 3
r = p; // line 4
With line 3 above, you are assigning the pointer q
to p
. But it doesn't change the type of p
- it's still a void pointer. So you can't dereference it. So the following is invalid:
printf("%d\n", *p); // p is a void pointer - dereferencing here is illegal
Alternatively, you can do:
printf("%d\n", *((int*) p)); // p is a void pointer
The above is valid. Because, we convert p
to int *
before dereferencing it. Consider an example,
void func(void *p)
{
// what's `p` point to here?
}
int main(void)
{
int i = 5;
long x = 10;
void *p;
p = &i; // line 1
p = &x; //line 2
func(p);
}
You can comment out either line1 or line2 but is there anyway in func()
to know whether p
is pointing to a long
data or int
data? This is no different to your case.
But the conversion from void *
to type *
(data pointer) is always necessary before accessing the data its pointing to. Note that it can't be any data pointer though. For example,
int i = 42;
float f = 4.0;
void *p = &f;
printf("%d\n", *((int*))p); // wrong!
This is illegal. p
points to a float *
. Dereferencing as if it's pointing to a int
data is wrong.
In the line " ?? ", is it legal to cast a pointer to a integer?
printf("%d\n", (int) *p);
Since p
being a void*
, you are not allowed dereference in the first place. The cast after dereferencing doesn't change anything and the dereferencing is illegal.
If you were to cast the pointer itself like:
printf("%d\n", (int)p);
This has implementation-defined behaviour in C. C also provides intptr_t
/uintptr_t
types for the integer to pointer conversions.
If a pointer p
has type void *
, then the expression *p
has type void
, and the void
type has no value1; that's why you have to convert the pointer to a "real" pointer type before dereferencing it.
Pointers and integers may be converted to each other, but the values are not guaranteed to be meaningful. However, that's not what the line marked ??
is doing; it's attempting to dereference p
and cast the result, but since p
is a pointer to void
, that's not allowed.
The expression *((int *) p)
casts p
from pointer to void
to pointer to int
and the dereferences the result. Since p
points to a
, this evaluates to the value of a
(2
).
void
type is an incomplete type that cannot be completed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With