Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confused about the pointers and generic(void) pointers in C

I missed a couple classes, and don't really understand the flowing lecture slide's examples about the void pointer.

  1. In the line "no,no,no", why we cannot deference P since P has been assigned a real pointer type q?

  2. 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?

  1. In the last line, I am confused about the expression. Is * ((int *)p) actually = p? Thanks!

enter image description here

enter image description here

like image 508
overloading Avatar asked Dec 06 '15 21:12

overloading


People also ask

Is generic pointer and void pointer are same?

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.

What is the difference between void and void 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).


Video Answer


4 Answers

"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.

like image 160
gnasher729 Avatar answered Sep 30 '22 09:09

gnasher729


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.

like image 25
J. Murray Avatar answered Sep 30 '22 10:09

J. Murray


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.

like image 27
P.P Avatar answered Sep 30 '22 09:09

P.P


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).


1. The void type is an incomplete type that cannot be completed.
like image 44
John Bode Avatar answered Sep 30 '22 09:09

John Bode