-4

I couldn't understand the first and second value of the output, why are they different ? What is the second output meaning here ? The Code is:

int **p = (int **)malloc(sizeof(int *) * 2);
int i, j, c = 1;

for (i = 0; i < 2; i++) {
    p[i] = (int *)malloc(sizeof(int) * 2);
}

for (i = 0; i < 2; i++) {
    for (j = 0; j < 2; j++) {
        p[i][j] = c++;
    }
}

printf("%d %d %d %d\n", (int)&p[0][0], (int)p, (int)*p, **p);

Output: 34439216 34439184 34439216 1

Am_I_Helpful
  • 18,735
  • 7
  • 49
  • 73
  • 6
    Don't use `%d` and cast pointers to `int`s. Use `%p` and cast the pointers to `void *`. I also recommend [not casting the result of `malloc`](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). – chris Aug 21 '14 at 19:45
  • 1
    Why it is being down-voted without even answering my question ? – Prakhar Agarwal Aug 21 '14 at 19:50
  • 2
    @PrakharAgarwal try explaining a bit more about what you don't understand. As you have written it (and if you add in some text to explain that casting pointers to int is unreliable) the answer would be "they are different because they point to different memory locations" and "it is the address stored in p". – M.M Aug 21 '14 at 19:55
  • 1
    I don't understand why they are pointing to different locations ? Aren't &p[0][0] and p supposed to contain the same value ? – Prakhar Agarwal Aug 21 '14 at 19:58
  • No, the straight forward-answer. I'm editing my answer NOW to make it clear for you... – Am_I_Helpful Aug 21 '14 at 19:59
  • Printing pointers with `"%d"` and a cast to `(int)`, though not optimal, is OK. Further, it is not central to the issue as to why `(int)&p[0][0], (int)p` differ. I am impressed that a new poster did a cast to `(int)` with `"%d"` rather than the usual first-timers `printf("%d", &p);` – chux - Reinstate Monica Aug 21 '14 at 20:09
  • 1
    `&p[0][0]` and `p` would indicate the same memory address (although of different types) if `p` were an array; however `p` is a pointer to an array of pointers, so `p` is the address of a pointer which points to the first element. – M.M Aug 21 '14 at 20:09
  • @chux he had that originally and edited it after chris's comment – M.M Aug 21 '14 at 20:10

1 Answers1

1

Alright. Let's talk about some basic issues first:

  1. On many systems, int will take up less room than void *. So you're possibly truncating your pointers when you print them. It's quite easy to fix that, so let's do it.

  2. Additionally, it's unnecessary to cast the value of malloc(), so let's get rid of that as well to clean up the code a bit.

  3. Finally, as chris notes, to use the %p format specifier, we need to cast the int ** and int * variables to void *.

Fixed foo.c

#include <stdio.h>
#include <stdlib.h>

int main() {

    int **p = malloc(sizeof(int *) * 2);
    int i, j, c = 1;

    for (i = 0; i < 2; i++)
        p[i] = malloc(sizeof(int) * 2);

    for (i = 0; i < 2; i++)
        for (j = 0; j < 2; j++)
            p[i][j] = c++;

    printf("%p %p %p %d\n", (void *) &p[0][0], (void *) p, (void *) *p, **p);
}

Which now outputs:

0x7fd193c03930 0x7fd193c03920 0x7fd193c03930 1

So now, your actual question:

First, let's talk about what address &p[0][0] points to. That's a fairly complicated expression, but we can reduce it using a fairly simple process such that we end up with *p or p[0].

&p[0][0] == &*(p[0] + 0) == p[0] + 0 == p[0] == *(p + 0) == *p

Looking at that, it should be pretty clear why &p[0][0] (the first argument) and *p (the third argument) print the same value.

Now, I don't see any good reason why p[0] should point to the same address as p. p and p[0] have been assigned values from separate calls to malloc().

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
  • 3
    `printf` still requires that you cast these pointers to `void *`. As it is, the types mismatch, which is explicitly stated as undefined behaviour. – chris Aug 21 '14 at 20:04
  • 2
    C11 §7.21.6.1/9 (for `fprintf`, which `printf` is defined in terms of): *If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.* Looking at `p` above, *The argument shall be a pointer to void.* – chris Aug 21 '14 at 20:08
  • Wow! That explains it :) – Prakhar Agarwal Aug 21 '14 at 20:13