Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointer to pointer issue

Tags:

c

pointers

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

like image 557
user2714949 Avatar asked Aug 25 '13 06:08

user2714949


1 Answers

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.

like image 192
verbose Avatar answered Oct 06 '22 06:10

verbose