Skip to main content
gamedev.net
🔒 Locked

Pointer to array

Started by godmodder 8 replies 1.2k views
Original Post
godmodder
godmodder
Hello, I'm having trouble understanding what the following does: int (*p)[3]; p = new int[5][3]; Some questions: 1) does this create an array of 3x5 or 5x3? I wrote a loop to initialize the array and then print the contents. Problem is: the loops for both sizes don't give any segfaults and display all values nicely. The program does crash when I do the same thing on static arrays. (compiler == GCC) 2) I know "p" is a pointer to an array of 3 ints after the declaration, how then can it be assigned an int[5][3]? 3) what goes on behind the scene? I know how memory allocation works with double pointers or with one giant array and indices, but what on earth goes on here? 4) can I delete this with one call "delete [] p"? Thanks, Jeroen
SiCrane
SiCrane
1) It contains five sets of 3 elements.
2) The same way that an int * can be assigned a int[5]. An array decays to a pointer to the first element. So an int[5][3] can decay to an int (*)[3].
3) It allocates 5 * 3 * sizeof(int) bytes, and the result of that allocation is assigned to p.
4) Yes.
Splinter of Chaos
Splinter of Chaos
The thing to understand here is that the fallowing two lines are functionally equal.

p = new int[5][3];
p = new int[3][5];

They both create an array that is actually sizeof(int) * 3 * 5, as SiCrane said.

The thing that's really important is what does p+1 point to?
DevFred
DevFred
Quote:
Original post by Splinter of Chaos
p = new int[5][3];
p = new int[3][5];

Those two lines should return arrays of different types. You should at least get a warning.
Brother Bob
Brother Bob
Of course the memory layout will me the same if you fill both with consecutive numbers from the very first element. That would make p = new int[15] just as much the same. But accessing the arrays will give you different values becuase of different dimensions.

The are different, and they are functionally different, becuase they all have different dimensions.
Zahlman
Zahlman
Just because two things will have the same size, and the same bit pattern, in memory at runtime, doesn't make them identical in C++. The type of an object is not generally represented with memory; it's a compile-time concept. int x[5][3] differs from int y[3][5] in that reinterpret_cast<char*>(x[1]) - reinterpret_cast<char*>(x[0]) != reinterpret_cast<char*>(y[1]) - reinterpret_cast<char*>(y[0]).
DevFred
DevFred
Quote:
Original post by Zahlman
int x[5][3] differs from int y[3][5] in that reinterpret_cast<char*>(x[1]) - reinterpret_cast<char*>(x[0]) != reinterpret_cast<char*>(y[1]) - reinterpret_cast<char*>(y[0]).

Those reinterpret_casts aren't necessary to prove a point:
#include <iostream>int main(){    int x[5][3];    int y[3][5];    std::cout << (x[1] - x[0]) << std::endl;    std::cout << (y[1] - y[0]) << std::endl;}
Splinter of Chaos
Splinter of Chaos
new int[5][3] and new int[3][5] are functionally the same. I never claimed that int[5][3] x or int[3][5] y was the same. In fact, I never actually said [5][3] and [3][5] were the same. I said they were FUNCTIONALLY THE SAME meaning the assembly code produced that creates the array is the same. Functionally, they are no different.

However, I wanted the OP to answer what p++ meant from his or her example (int (*p)[3];). I didn't want to spark a holy war over semantics.

#include <iostream>int main(){    int (*p)[3];    int (*o)[5];    p = new int[5][3];    o = reinterpret_cast<typeof(o)>( new int[5][3] );     std::cout << std::endl;    std::cout << ((p+1) - p) << std::endl;    std::cout << (++o - --o) << std::endl;}


I think the output is actually pretty interesting.

EDIT

What I think is pretty interesting is how no matter how that is written, the answer is one because the pointer units are one. I forgot that when I copied DevFred's code to test it, but then remembered a lazy way around that was casting to an int. HERE is what I find interesting:
#include <iostream>#define TO_INT(num) reinterpret_cast<int>(num)int main(){    int (*p)[3];    int (*o)[5];    int* a;    p = new int[5][3];    o = reinterpret_cast<typeof(o)>( new int[5][3] );     a = new int[15];    std::cout << std::endl;    std::cout << (TO_INT(&p[1]) - TO_INT(p)) << std::endl;    std::cout << (TO_INT(&o[1]) - TO_INT(o)) << std::endl;    std::cout << (TO_INT(&a[1]) - TO_INT(a)) << std::endl;    delete [] p;    delete [] o;    delete [] a;}


[Edited by - Splinter of Chaos on December 11, 2008 2:18:30 AM]
Brother Bob
Brother Bob
Quote:
Original post by Splinter of Chaos
new int[5][3] and new int[3][5] are functionally the same. I never claimed that int[5][3] x or int[3][5] y was the same. In fact, I never actually said [5][3] and [3][5] were the same. I said they were FUNCTIONALLY THE SAME meaning the assembly code produced that creates the array is the same. Functionally, they are no different.

Personally, I never claimed that you clamined that they were the same. But your definition of "functionally the same" is very strange. Why, for any reason, would the assembly code is required to create the arrays be important in a language designed to abstract assembly language? And how do you know that there's no difference in any of the several platforms in existance, where there's also a C++ compiler? By that definition, everything is the same. The assembly code to create any integer array is the same. So that would make any integer array functionally the same, not just the two you're talking about.

On any level other than the assembly required to allocate the arrays, they are different. Yes, functionally different. The pointer types returned by new are incompatible, and the usages are different.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.