Вопрос

I need to understand why assigning void* to int** will work, but when printing the value of int**, it will not work. Here's the code:

int k = 3;
int *l = &k;
void *a = l; 
int **c = a; // if I assign, &a, the below line work, but get warning: incompatible
             // pointer type.
printf("%d", **c); // Code break;

But this line

printf("%d", *c); // will work, but get warning "%d expect int but of type int *".

Update: I saw this type of code in OOC book where author do this:

struct Class {
   size_t size;
   int (*differ)(const void *self, const void *b);
   ..... Some more code ....

};

int differ(const void *self, const void *b) {
  // Note this line
  const struct Class **cp = self;
  assert(self && *cp && (*cp)->differ);
  return (*cp)->differ(self, b);
}
Это было полезно?

Решение

You have this situation:

+---+
| l | --\
+---+    \     +---+
          >--> | k |
+---+    /     +---+
| a | --/
+---+

I.e. both l and a points directly to k.

When you then do

int **c = a;

you make c point to what a is pointing to as well (i.e. it's the same as doing int **c = &k), but you declare c to be a pointer to pointer to an int, but make it point directly to an int. That means using single dereference (*c) you get the value of k, and when you you use double dereference (**c) you use the value of k as a pointer (which it isn't).

I assume what you really want is this situation:

+---+     +---+     +---+
| a | --> | l | --> | k |
+---+     +---+     +---+

which you will get by doing

void *a = &l;

Then using c as a pointer to pointer will work because then a is a pointer to a pointer.


If you continue with the first scenario, where you have

int   k;
int  *l = &k;
void *a = l;

and then do

int **c = (int **) &a;  // The typecast is needed

Then you have the following situation:

          +---+
          | l | --\
          +---+    \     +---+
                    >--> | k |
+---+     +---+    /     +---+
| c | --> | a | --/
+---+     +---+

This will work because then c really is a pointer to a pointer to something.

Другие советы

This is why you have to be careful with void* pointers. You can assign any pointer to them, and you can assign them to any other pointer. Even if it doesn't make sense (like your example).

When you assign int **c = a, you've committed an error, that I think you're already aware of. You've changed levels of indirection (a came from an int*, but you're assigning it to an int**), but didn't take another address-of (&).

Your program fails for the same reason that, if you eliminated the void* a, and instead tried this, it would fail.

int k = 3;
int *l = &k;
int **c = l;    // Error - wrong level of indirection.

This is low-level C. Just because the compiler lets you do something doesn't mean it will work.

The solution to this question is: Don't do it.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top