stuck with a trivia
-
//Works
int py[5] = {0,1,2,3,4}; int* pyp = (int*)py;//py printf("%d",pyp[2]);
//Doesn't.show "2Dpointer\n"; int py2[2][2] = {0,1,2,3}; int **pyp2 = (int**)py2; printf("py2:%d",py2); printf("pyp2:%d",pyp2); printf("**pyp2[0][0]",pyp2[0][0]);//Crash printf("**pyp2%d",**pyp2);//Crash `why? :beer: `
-
//Works
int py[5] = {0,1,2,3,4}; int* pyp = (int*)py;//py printf("%d",pyp[2]);
//Doesn't.show "2Dpointer\n"; int py2[2][2] = {0,1,2,3}; int **pyp2 = (int**)py2; printf("py2:%d",py2); printf("pyp2:%d",pyp2); printf("**pyp2[0][0]",pyp2[0][0]);//Crash printf("**pyp2%d",**pyp2);//Crash `why? :beer: `
All index [] notation is converted to pointer arithmetic. So, you declare int py2[2][2]; the compiler knows the total size (2*2 = 4) and how wide each row is (2). So if you do py2[1][0] the compiler can convert to py2 + (1*2) + 0 But then you do int **pyp2 = py2; Now you have created an alias and lost all information about the dimensions of the array. So, when you try to do pyp2[0][0] the compiler can only get to pyp2 + (0*?) + 0 it doesn't know what to fill in for ?
...cmk The idea that I can be presented with a problem, set out to logically solve it with the tools at hand, and wind up with a program that could not be legally used because someone else followed the same logical steps some years ago and filed for a patent on it is horrifying. - John Carmack
-
//Works
int py[5] = {0,1,2,3,4}; int* pyp = (int*)py;//py printf("%d",pyp[2]);
//Doesn't.show "2Dpointer\n"; int py2[2][2] = {0,1,2,3}; int **pyp2 = (int**)py2; printf("py2:%d",py2); printf("pyp2:%d",pyp2); printf("**pyp2[0][0]",pyp2[0][0]);//Crash printf("**pyp2%d",**pyp2);//Crash `why? :beer: `
py2 is an address. The contents of py2 are 0, 1, 2, 3. Agreed ? pyp2 is a pointer to a pointer. pyp2 is initialized with the address of py2. Now when you say *pyp2 it is taking the first value of 0 which it thinks is another address. So, **pyp2 is trying to read the value at address 0. // Crash If the contents of py2 were 5, 6, 7, 8, **pyp2 will be trying to read the value at address 5. // Still Crash.
«_Superman_»
-
//Works
int py[5] = {0,1,2,3,4}; int* pyp = (int*)py;//py printf("%d",pyp[2]);
//Doesn't.show "2Dpointer\n"; int py2[2][2] = {0,1,2,3}; int **pyp2 = (int**)py2; printf("py2:%d",py2); printf("pyp2:%d",pyp2); printf("**pyp2[0][0]",pyp2[0][0]);//Crash printf("**pyp2%d",**pyp2);//Crash `why? :beer: `
py2
is anint *
, not anint **
. Extra dimensions of arrays DO NOT imply extra indirection (i.e. extra levels of pointer). Therefore your C cast when assigningpy2
topyp2
is breaking the type safety that's trying to tell you what your mistake is. -
All index [] notation is converted to pointer arithmetic. So, you declare int py2[2][2]; the compiler knows the total size (2*2 = 4) and how wide each row is (2). So if you do py2[1][0] the compiler can convert to py2 + (1*2) + 0 But then you do int **pyp2 = py2; Now you have created an alias and lost all information about the dimensions of the array. So, when you try to do pyp2[0][0] the compiler can only get to pyp2 + (0*?) + 0 it doesn't know what to fill in for ?
...cmk The idea that I can be presented with a problem, set out to logically solve it with the tools at hand, and wind up with a program that could not be legally used because someone else followed the same logical steps some years ago and filed for a patent on it is horrifying. - John Carmack
but why does it work here ?
int py[5] = {0,1,2,3,4}; int* pyp = (int*)py;//py printf("%d",pyp[2]);
As it shows, the memory has been laid out for these values, [START_ADDRESS]4bytes,4bytes,4bytes,4bytes,4bytes. So when you assign the pointer, it starts to point to the first item. Further when you make a pyp++ or pyp[], it's landing up on the right element. Here too, I'm not passing it any information about the size of the array. It's just the pointer and it's taking it up. 2D arrays, it's not too different from 1D. The next batch of numbers would be following.. err.. err. Okay as I'm typing this I'm getting it :D ..I'm not giving it any clue where the first row ends.. well..is that what you mean? sounds convincing but why not it work atleast for the first item? I'm just saying **pyp2. Just trying to get the value of the element it's currently pointing to. Why even this doesn't work? btw, why the complier is not warning me about a meaningless assignment?:beer:
-
py2
is anint *
, not anint **
. Extra dimensions of arrays DO NOT imply extra indirection (i.e. extra levels of pointer). Therefore your C cast when assigningpy2
topyp2
is breaking the type safety that's trying to tell you what your mistake is.argh okay. accepted. is there way I can do it? I think it can be done by allocating a memory of that dimension dynamically and assigning the pointers one by one.bullshit. I meant assigning the pointers.
:beer:
modified on Wednesday, February 4, 2009 4:02 AM
-
py2 is an address. The contents of py2 are 0, 1, 2, 3. Agreed ? pyp2 is a pointer to a pointer. pyp2 is initialized with the address of py2. Now when you say *pyp2 it is taking the first value of 0 which it thinks is another address. So, **pyp2 is trying to read the value at address 0. // Crash If the contents of py2 were 5, 6, 7, 8, **pyp2 will be trying to read the value at address 5. // Still Crash.
«_Superman_»
-
So, **pyp2 is trying to read the value at address 0. // Crash Why should it crash? *pyp2 = first row. **pyp2 = first element of the first row. What's wrong with it?
:beer:
Smith# wrote:
*pyp2 = first row. **pyp2 = first element of the first row.
Wrong. I have tried to explain it in my previous post.
«_Superman_»
-
Smith# wrote:
*pyp2 = first row. **pyp2 = first element of the first row.
Wrong. I have tried to explain it in my previous post.
«_Superman_»
Now when you say *pyp2 it is taking the first value of 0 which it thinks is another address. Yes. that's the address of the first pointer. I called it as 1st row. With **pyp2, I try to access the first element. in other words, *pyp2[0]. I agree that you cannot ask it go to the next pointer since it doen't know where first one ends. But what's the problem to access the "first-most" element? We have the address, what's the problem with taking it's address? Am I still missing something?
:beer:
-
Now when you say *pyp2 it is taking the first value of 0 which it thinks is another address. Yes. that's the address of the first pointer. I called it as 1st row. With **pyp2, I try to access the first element. in other words, *pyp2[0]. I agree that you cannot ask it go to the next pointer since it doen't know where first one ends. But what's the problem to access the "first-most" element? We have the address, what's the problem with taking it's address? Am I still missing something?
:beer:
To access the first element you simply do *pyp2. Try it.
«_Superman_»
-
To access the first element you simply do *pyp2. Try it.
«_Superman_»
-
argh okay. accepted. is there way I can do it? I think it can be done by allocating a memory of that dimension dynamically and assigning the pointers one by one.bullshit. I meant assigning the pointers.
:beer:
modified on Wednesday, February 4, 2009 4:02 AM
Try initialising pyp2 like this:
int p1[2] = { 1, 2 };
int p2[2] = { 1, 2 };
int* pyp2[2] = { p1, p2 };pyp2 is of type
(int*)[2]
, which is equivalent toint **
. -
It is giving me the value. Try to understand that this is exactly why your code is crashing.
«_Superman_»
-
Try initialising pyp2 like this:
int p1[2] = { 1, 2 };
int p2[2] = { 1, 2 };
int* pyp2[2] = { p1, p2 };pyp2 is of type
(int*)[2]
, which is equivalent toint **
. -
Try initialising pyp2 like this:
int p1[2] = { 1, 2 };
int p2[2] = { 1, 2 };
int* pyp2[2] = { p1, p2 };pyp2 is of type
(int*)[2]
, which is equivalent toint **
. -
It is giving me the value. Try to understand that this is exactly why your code is crashing.
«_Superman_»
-
//Works
int py[5] = {0,1,2,3,4}; int* pyp = (int*)py;//py printf("%d",pyp[2]);
//Doesn't.show "2Dpointer\n"; int py2[2][2] = {0,1,2,3}; int **pyp2 = (int**)py2; printf("py2:%d",py2); printf("pyp2:%d",pyp2); printf("**pyp2[0][0]",pyp2[0][0]);//Crash printf("**pyp2%d",**pyp2);//Crash `why? :beer: `
The key point is that arrays and pointers are NOT the same. An array can be converted into a pointer and pointer arithmetic (and indexing) looks the same as array subscripting, but they aren't. They coincide only for linear indexing (that's the case of monodimensional arrays) int **pyp2 is a "[pointer to a [pointer to [an int]]]" The memory layout it expects is like
int** ----> [int*, int*, int*, ...]
| | |
| | |
| | V
| V [int,int,...]
V [int,int,int...]
[int, int, ...]While int py2[2][2] is an "[array of [array of [int]]]" The memory layout it expects is like
[[int,int],[int,int]]
That's completely different.
2 bugs found. > recompile ... 65534 bugs found. :doh:
-
The key point is that arrays and pointers are NOT the same. An array can be converted into a pointer and pointer arithmetic (and indexing) looks the same as array subscripting, but they aren't. They coincide only for linear indexing (that's the case of monodimensional arrays) int **pyp2 is a "[pointer to a [pointer to [an int]]]" The memory layout it expects is like
int** ----> [int*, int*, int*, ...]
| | |
| | |
| | V
| V [int,int,...]
V [int,int,int...]
[int, int, ...]While int py2[2][2] is an "[array of [array of [int]]]" The memory layout it expects is like
[[int,int],[int,int]]
That's completely different.
2 bugs found. > recompile ... 65534 bugs found. :doh:
As you know pointers & arrays both move consecutive. Then how come it be totally different? To some extent I can agree. Because the next pointer in the **ptr can be made to point to some other *p pointing somewhere. But here that's not the case.. it's array, quite consecutive and we are making our **ptr point to it. What do you think about the below approach ? getting the address of the first row pointer & getting the address of it and then deferencing.
int py2[2][2] = {10,11,12,13}; int* sptr = &py2[0][0]; int** dptr = &sptr; printf("\nAtlast:%d\n",**dptr); *dptr+=1; *dptr+=2; printf("\nAtlast:%d\n",**dptr);
:beer:
-
As you know pointers & arrays both move consecutive. Then how come it be totally different? To some extent I can agree. Because the next pointer in the **ptr can be made to point to some other *p pointing somewhere. But here that's not the case.. it's array, quite consecutive and we are making our **ptr point to it. What do you think about the below approach ? getting the address of the first row pointer & getting the address of it and then deferencing.
int py2[2][2] = {10,11,12,13}; int* sptr = &py2[0][0]; int** dptr = &sptr; printf("\nAtlast:%d\n",**dptr); *dptr+=1; *dptr+=2; printf("\nAtlast:%d\n",**dptr);
:beer:
It seems you're confusing two well distinct concepts (don't worry: it takes about three years to me to get away from that confusion...). Let's reconsider your points:
Smith# wrote:
As you know pointers & arrays both move consecutive
No. Pointers "move" (in th sense they can receive another address as their own stored value). Array just "are". Array indexes "move" (in the sense they can be used to indicate other array cells).
Smith# wrote:
how come it be totally different
Because they ARE totally different. They simple have a "similar" external interface (same operators).If you don't get this point may be I was not able to explain the first point, but until you don't get it you cannot move away from your trivia. So loop over and over until you get it, find other sources than me (if you find my way to explain is not clear) but there is no way to move over until this crucial point is clear.
Smith# wrote:
Because the next pointer in the **ptr can be made to point to some other *p pointing somewhere. But here that's not the case.. it's array,
You know, but compiler doesn't.
int**
for the compiler is just 4 bytes of memory containing the address of an int* that is another 4 byte of memory, somewhere else, containing the address of an int. Whatever you think about this is irrelevant to the compiler.int[]
is a consecutive bounce of integers at some place in memory. This place has an address. When you doint a[2] = { 0,1 };
int* pa = a;you assign the address of the array head to the pointer. When you do
*pa = 5;
the compiler assign
5
to the memory whose address is stored in "pa". This accidentally is a[0] (but it is not something the compiler is aware of). When you dopa[1] = 6;
the compiler assign 6 to the memory whose address is given by
pa+1*sizeof(int)
, that accidentally is a[1] (again you know, not the compiler: there is nothing in "pa" that makes the compiler aware of the fact that it is NOW pointing to an array and sometime later on to an individual integer and some later on to an integer inside a class or struct. The design of the [] operator appllied to poitner or to array makes this operation giving a same result just because for monidimensional array, the same calculation is done. Bidimensional arra -
As you know pointers & arrays both move consecutive. Then how come it be totally different? To some extent I can agree. Because the next pointer in the **ptr can be made to point to some other *p pointing somewhere. But here that's not the case.. it's array, quite consecutive and we are making our **ptr point to it. What do you think about the below approach ? getting the address of the first row pointer & getting the address of it and then deferencing.
int py2[2][2] = {10,11,12,13}; int* sptr = &py2[0][0]; int** dptr = &sptr; printf("\nAtlast:%d\n",**dptr); *dptr+=1; *dptr+=2; printf("\nAtlast:%d\n",**dptr);
:beer:
Now, let's move a little bit on: If you agree with my previous post, consider this:
int a [2][2] = { 1,2,3,4 };
int[2]* ppa = a;Do you get it? Instead of int**, I use int[2]*: a "pointer to an array of two integers". considering the int[][] as "array of 2 arrays of two integers". The type of int** is int* (that doesn't exist in memory since we store arrays), but the value of int[2]* is int[2] that's just one row of the matrix ( in our case
{{1,2},{3,4}}
Now ppa[1][1] is "take the address stored in ppa, add 1*sizeof(int[2]). This is the int[2] representing the second row. Now we're anymore dealing with a pointer, but with an array, whose cell "1" has the value "4".2 bugs found. > recompile ... 65534 bugs found. :doh: