tags:

views:

99

answers:

4

This is probably a stupid question, but I don't understand why this works:

 int** test = new int*[7];

 int x = 7;
 *(test+1) = &x;

 cout << (**(test+1));

test is a pointer to a pointer right? The second pointer points to the array, right? In my understand I would need to dereference the "test" pointer first to get to the pointer that has the array.

(*test) // Now I have int*
*((*test) + 1) // to access the first element.

Where is my faulty thinking?

A: 

The expression *(test + 1) is equivalent to test[1], so your code could be rewritten thus:

int** test = new int*[7];

int x = 7;
test[1] = &x;

cout << *test[1];

Since test[1] obviously points to x, *test[1] is 7.

Just to be clear, the expression **(test + 1) is simply equivalent to *(*(test + 1)), which is in turn equivalent to *test[1].

Marcelo Cantos
@Marcelo: I know that. What I don't understand is why test[1] points to something sensible. In my understanding test is a pointer to a pointer, which in turn has a bunch of memory laid out. Like this: test->array[0][1][2][3][..] Calling test[1] should not do anything, I thought that I would need to call array[1].
Blub
+1  A: 

Suppose that

test[0] = 0x12345678;   // some pointer value
test[1] = 0x23456789;   // some pointer value

*test = 0x12345678;

*test + 1 is now 0x12345678 + 1 = 0x12345679;

* or dereference operator has higher precedence than binary +). So the expression is evaluated in that order.

However what you wanted for is to get to test[0] = 0x23456789;

So the correct expression to get to test[1] = (*(test + 1))

In general arr[i] is *(arr + i)

EDIT 2:

given

int buf[10] = {0, 1, 2};
int *p = buf;

buf[0] == p[0] == *(p + 0) equal to 0.

Note that it is perfectly fine to use array access syntax with the lvalue expression p even if it is not an array type. In fact the expression buf[0] is internally translated by the compiler to *(buf + 0) as well.

Chubsdad
@chubsdad: Please see my comment to Marcelo. I dont understand why I should be able to dereference test like it was an array with []. In my understanding test is not an array, it's a pointer. The array is inside the second pointer.
Blub
@Blub: For a given 'p' such that 'T *p;', where 'T' is a non void type, and an integral expression 'i', the expression `p[i]` basically is equivalent to `*(p+i)`. The compiler does not restrict this syntax only for statically known array type objects. The fact that `p[i]` in turn is also a pointer to an array does not change the basic rule `p[i] = *(p+i)`
Chubsdad
+7  A: 

Is your misunderstanding that you think you have created a pointer to an array of 7 int? You haven't. You actually have created an array of 7 pointers to int. So there is no "second pointer" here that would point to an array. There is just one pointer that points to the first of the 7 pointers (test).

And with *test you get that first pointer which you haven't initialized yet, though. If you would add 1 to that, you would add 1 to some random address. But if you add 1 to test you get a pointer that points to the second pointer of the array. And dererencing that you get that second pointer, which you did initialize.


What you describe would be achieved by a different syntax

typedef int array[7];
array* test = new int[1][7];

// Note: "test" is a pointer to an array of int. 
// There are already 7 integers! You cannot make it
// point to an int somehow. 
*(*test + 1) = 7;

int *p1 = *test
int i1 = *(p1 + 1); // i1 is 7, second element of the int[7]

delete[] test;

Without using the typedef, this looks like the following

int(*test)[7] = new int[1][7];

That is, you have created a one-element array, where the element-type of that is a 7-element array of int. new gives you a pointer back to that array. Note that the parenthesis is important: The * has less precedence than the [7], so otherwise this would be taken as an array of 7 pointer to integers.

Johannes Schaub - litb
@Johannes: int(*test)[7] is a pointer to int[7] right? How is it possible that a one dimensional array houses two dimensions... I think you just found another thing I don't get. But I understand my initial problem now :) Recapping for myself: Pointer arithmetics work by adding a byte offset to a memory address. An uninitialized pointer doesnt point to anything yet, so I can't use pointer math on it.
Blub
I couldn't find any advanced tutorials on the net which deal with fine syntax changes like int(*test)[] and int*test[] differences. Do you have a suggestion where I can read up on that?
Blub
@Blub it doesn't really house two dimensions. It's like `int *p = new int[1];`. You could ask "how could a scalar house an array?". The answer is that it's the other way around: The array houses the scalar (which "p" points to), and the 2-dim array houses the 1-dim array (which we point to).
Johannes Schaub - litb
+3  A: 

int** test = new int*[7];

+------++------++------++------++------++------++------+
| int* || int* || int* || int* || int* || int* || int* |
+------++------++------++------++------++------++------+

is the equivalent of an array with int pointers:

int* test[0] 
int* test[1] 
...
int* test[6] 

this

int x = 7;
 *(test+1) = &x;

+------++------++------++------++------++------++------+
| int* || &x   || int* || int* || int* || int* || int* |
+------++------++------++------++------++------++------+

is the same as

int x = 7;
test[1] = &x

so now one of the pointers in your original array is pointing the memory location of x

 cout << (**(test+1));

is the same as

cout << *test[1] 

which is the value of x (==7) and which both test[1] and &x point to.

Anders K.
+1 for the ASCII art
Chubsdad