5

I created a pointer to pointer and a int array, but when I try to access the array via my pointer to pointer, it skips some elements and moves by two elements at a time (eg: from 1 to 3). Here is my code:

int main(void) {
    int c=10;
    int p[5]={2,3,5,6,8};
    int *x;
    int **y;
    x=p;
    y=&p;
    printf("p value is %d and p points to %d",p,&p);
    printf("\n x is %d \n",x[1]);
    printf("\n y is %d \n",y[0]);

    return 0;
}

When I print y[1] it will print 5 instead of 3 and y[2] is printed as 8. I can't think of the reason. Can any one help me on this? Pointer x is is working fine and moves along the correct elements as x[0]=2, x[1]=3, x[5]=5. also can any one explain why i get same value for p and &p

user2714949
  • 399
  • 2
  • 3
  • 11
  • 4
    Not `double pointer` correct word is `pointer to pointer` – Grijesh Chauhan Aug 25 '13 at 06:48
  • 3
    I *love* double pints, especially when they're a real nice, hoppy IPA. – WhozCraig Aug 25 '13 at 06:49
  • 2
    Try `y = &x;` You may have better luck. And print anything you're passing that should be a "pointer" with `%p`. You'll be glad you did. – WhozCraig Aug 25 '13 at 06:52
  • Are you sure `p` is a pointer? – Lasse V. Karlsen Aug 25 '13 at 06:52
  • 1
    The trouble with the term `double pointer` is that it is ambiguous between `double *` and `sometype **`. The term is used informally for the double-star notation (and triple pointer for uses of [`sometype ***`](http://c2.com/cgi/wiki?ThreeStarProgrammer)), but it is probably better to use 'pointer to pointer' to avoid misinterpretation in formal contexts like SO questions. – Jonathan Leffler Aug 25 '13 at 06:54
  • you must getting error/warning for `y=&p;` as @WhozCraig commented you might probably wants `y = &x` – Grijesh Chauhan Aug 25 '13 at 06:56
  • @GrijeshChauhan: OP is using C and not C++. – Alok Save Aug 25 '13 at 06:57
  • 1
    @AlokSave **Yes**, C ... ?? did not get you! – Grijesh Chauhan Aug 25 '13 at 06:58
  • 3
    @LasseV.Karlsen: `p` without a subscript is an `int *`. There are numerous attempts to print pointers with the `%d` notation. This is very bad on 64-bit systems, and not particularly good on 32-bit systems. – Jonathan Leffler Aug 25 '13 at 07:01
  • 2
    y[1] would be entirely different thing than what you expect it to be. It is represents the pointer next to pointer p in memory. Which would contain garbage value. when you will run it few times more you would see its value keeps changing – Himanshu Pandey Aug 25 '13 at 07:31
  • 1
    I don't think there is any ambiguity in "double pointer" - anyone at least remotely familiar with C or C++ knows it is a `double *`. Using it for `**` is completely illogical, the location of a location to a location is not "double location"... – dtech Aug 25 '13 at 07:43

4 Answers4

5

Okay, this question has been answered and an answer has been accepted, but even the accepted answer does not explain the weird results the original poster was seeing: why do y[1] and y[2] print 5 and 8? Here is the explanation.

Original poster: What output do you get from the following statements?

printf ("Size of integer: %zu\n", sizeof (int));
printf ("Size of pointer: %zu\n", sizeof (int*));

I'm going to bet that the output is:

Size of integer: 4
Size of pointer: 8

In other words, I'm guessing that you're compiling on a 64-bit machine where the size of an integer is 4 bytes and the size of a pointer is 8 bytes. Based on that assumption, here's what is happening.

p is an array. With a few exceptions, when used in any expression, the array's name "decays" to a pointer to its first element. Any time you access the value of p, therefore, it will yield the address of its first element.

&p is one of those exceptions to the rule about arrays "decaying" to pointers. The address-of operator, when applied to an array's name, returns a pointer to the entire array--not a pointer to a pointer to the first element of the array.

What this means is that p and &p have the same value, but they are semantically very different. You will get the same value when you print:

 printf("p value is %p and p points to %p", p, &p);  // use %p and not %d for addresses

However, this does not mean that p and &p refer to the same thing. p is the address of first element of the array, i.e., &p[0]. On the other hand, &p is the address of the entire array of 5 integers.

So when you define x and y as follows:

int* x = p;
int** y = &p;

x is assigned a pointer to the first element of the array; y is assigned a pointer to the entire array. This is an important difference!

There is, moreover, a mismatch between how y is declared, and the value you're assigning to it. &p is of type int (*) [5]; a pointer to an array of 5 int. y is merely a pointer to a pointer to a single int. Your compiler should give you a warning about this mismatch. Mine does:

Warning: incompatible pointer types assigning to 'int**' from 'int (*) 5'

This mismatch explains the weird results while printing values of y[1] and y[2]. Let's look at what's going on with the values.

As you know, array subscripts are offsets from the beginning of the array:

x[0] == *(x + 0)

So x[0] yields the first element of the array, i.e., 2. Similarly

x[1] == *(x + 1)

But x is a pointer to int. So what is actually happining in the addition x + 1? Remember how pointer arithmetic works. Adding an integer to a pointer means you're actually adding that integer times the size of the element pointed to. In this case:

x + 1 == x + (1 * sizeof(int))

Since sizeof(int) is 4 on your system, the value of x[1] is the next integer in the array, which is 3.

So then, when you print y[0], how is this evaluated?

y[0] == *(y + 0)

Hence, the value that is at the address pointed to by y, i.e., at the address of p, is printed. This is the first element of p, hence you get the result 2.

What happens when you print y[1]?

y[1] == *(y + 1)

But what is y? It is a pointer to a pointer to an int. So when you add 1 to y, the way pointer arithmetic works is it again adds 1 * the size of the type of the element pointed to.

y + 1 == y + (1 * sizeof (int*))

The size of an int* is 8 bytes, not four! So every time you increment y by 1, you're incrementing it by 8 bytes, or the size of two integers. Hence, when you dereference that value, you are getting not the next integer in the array, but the integer that is two away.

To explain more clearly: Let us assume that the array begins at element 1000. Then, because each int takes four bytes, the following is the case:

 Address      Element
-----------------------
  1000          2
  1004          3
  1008          5
  1012          6
  1016          8


 p == &p == x == y == 1000
 *x == *y == 2

When you add 1 to x, you are adding 1 * sizeof(int), i.e., you are actually adding 4. So you get 1004, and *(x + 1), or x[1], gives you 3.

But when you add 1 to y, you are adding 1 * sizeof(int*), i.e., you are actually adding 8. So you get 1008, and *(y + 1) gives you the element at address 1008, or 5.

This explains the output you are getting. This is NOT, however, a reasonable way to code. You should not expect that the size of a pointer is always going to be 8 bytes. You should not assign an int (*) [] to an int**. You should not dereference a pointer to a pointer to an int and expect to get an int result. And always heed compiler warnings.

verbose
  • 7,827
  • 1
  • 25
  • 40
4

This at least gives a clean compilation and uses %p to print pointers:

#include <stdio.h>

int main(void)
{
    int p[5]={2,3,5,6,8};
    int *x = p;
    int **y = &x;
    printf("p value is %p and the address of p is %p and p points to %d\n", (void *)p, (void *)&p, *p);
    printf("x[1] is %d\n", x[1]);
    printf("y[0] is the address %p\n", (void *)y[0]);
    printf("y[0][0] is %d\n", y[0][0]);

    return 0;
}

Sample output (Mac OS X 10.8.4, GCC 4.8.1, 64-bit compilation):

p value is 0x7fff5a1a54d0 and the address of p is 0x7fff5a1a54d0 and p points to 2
x[1] is 3
y[0] is the address 0x7fff5a1a54d0
y[0][0] is 2
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • thanks i got it.y[1] points to the next memory address.since mine is a 64 bit. 2 int values are saved in the same memory block. correct – user2714949 Aug 25 '13 at 08:15
  • 1
    If you're using a 64-bit compilation, then usually, `sizeof(int) == 4` and `sizeof(Anything *) == 8`, so you can regard that as '2 `int` values are saved in one pointer' — it's a little sloppy, but is not sufficiently inaccurate to matter. – Jonathan Leffler Aug 25 '13 at 15:49
4

Remember array name can easily decays into pointer to first element in most expressions. p[] array in memory is like (addresses are assumption):

  p 
 200   204 208  212  216 
+----+----+----+----+---+
|  2 |  3 | 5  | 6  | 8 |
+----+----+----+----+---+
  ▲    ▲    ▲    ▲    ▲
  |    |    |    |    | 
  p    p+1  p+2  p+3  p+3

After x = p;, x also pointer to first element.

  p 
 200   204 208  212  216 
+----+----+----+----+---+
|  2 |  3 | 5  | 6  | 8 |
+----+----+----+----+---+
 ▲ ▲   ▲    ▲    ▲    ▲
 | |   |    |    |    | 
 | p   p+1  p+2  p+3  p+3
 |
 x 
+----+
| 200|
+----+

In expression y = &p; , &p is pointer of array of type int(*)[5] and y is int**. (you must getting a warning (or error) compile with -Wall).

Read: Difference between &p and p

Because value-wise both p and &p are same so address value of y is also same as p.

  p 
 200   204 208  212  216 
+----+----+----+----+---+
|  2 |  3 | 5  | 6  | 8 |
+----+----+----+----+---+
 ▲ ▲   ▲    ▲    ▲    ▲
 | |   |    |    |    | 
 | p   p+1  p+2  p+3  p+3
 |
 x         y
+----+    +----+
| 200|    | 200|
+----+    +----+
 int*      int**

Your first printf:

 printf("p value is %d and p points to %d",p,&p);

Should be written as:

 printf("p value is %p and p points to %p", (void*)p, (void*)&p);
 //                  ^                  ^  

Use %p instead of %d because you are printing addresses also typecast to void* is necessary because %p expects void*. As I said value-wise p and &p are same both addresses are same.

Second printf:

printf("\n x is %d \n", x[1]);

Outputs: 3 as x points to first element in array x[1] == *(x + 1) == 3 (in my figures x + 1 == 204).

Third printf:

printf("\n y is %d \n", y[0]);

Note y type is int** so y[0] == *(y + 0) = *y value stored at y type of *y is int*.
So again because y[0] is int* you should use %p instead of %d.

But the above printf statement prints value of first element that is: 2.

Similarly y[1] prints 3 and y[2] prints 5.

Edit

When I print y[1] it will print 5 instead of 3 and y[2] is printed as 8.

No, It outputs as I explained above Check @codepade where sizeof(int) == sizeof(int*) probably in your system sizeof(int*) = twice of sizeof(int) (64-bit compiler) so when you add one you address next to next location.

As @WhozCraig commented: Try y = &x; You may have better luck. And print anything you're passing that should be a "pointer" with %p.

Correct your code.

Community
  • 1
  • 1
Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
  • 1
    "In expression `y = &p;` , `&p` is pointer of array of type `int(*)[5]`, but in assignment `int(*)[5]` decays into `int**`." I am not sure this is correct. A pointer to an array is a pointer, not an array. So it will not decay. I think the assignment here is between incompatible pointer types and will cause erratic behavior. Please see my answer for a fuller discussion. Thanks! – verbose Aug 25 '13 at 09:00
  • @verbose user formatting tips for programming codes use as `\`int(*)[5]\`` . Let me read your comment again. – Grijesh Chauhan Aug 25 '13 at 09:02
  • @verbose actually word decay is wrong here. Give me a minute I correct it – Grijesh Chauhan Aug 25 '13 at 09:04
0

I think you code cann't compile successfully. The type of &p is char (*p)[10], but the type of y is char **,

cannot convert from 'char (*)[10]' to 'char **'
BlackMamba
  • 10,054
  • 7
  • 44
  • 67