views:

319

answers:

9

I have a 3x3 array that I'm trying to create a pointer to and I keep getting this array, what gives?

How do I have to define the pointer? I've tried every combination of [] and *.

Is it possible to do this?

int tempSec[3][3];

int* pTemp = tempSec;
+14  A: 

You can do int *pTemp = &tempSec[0][0];

If you want to treat a 3x3 array as an int*, you should probably declare it as an int[9], and use tempSec[3*x+y] instead of tempSec[x][y].

Alternatively, perhaps what you wanted was int (*pTemp)[3] = tempSec? That would then be a pointer to the first element of tempSec, that first element itself being an array.

You can in fact take a pointer to a 2D array:

int (*pTemp)[3][3] = &tempSex;

You'd then use it like this:

(*pTemp)[1][2] = 12;

That's almost certainly not what you want, but in your comment you did ask for it...

Steve Jessop
So those are my two choices? There is no way to create a pointer to a 2D array?
cam
Yes, but it won't have type `int*`. I can't tell which parts of your question are the parts you want, and which you don't...
Steve Jessop
Doing it this way you throw away any inofrmation about the layout of the data. Now you can not tell that it is a three by three array.
Martin York
Sure: a true pointer to a 2D array would be `int (*pTemp)[3][3] = `. Pointers-to-arrays are used so rarely that without more context, I have no idea whether the questioner really wants an `int*` as the question title suggests, or not, and if not what type he should use.
Steve Jessop
A true pointer to a 2D array is an `int**`, however, you will need to create an array of pointers first. See my answer for details.
DoctorT
@DoctorT. No, an `int**` is not a true pointer to a 2D array. It is a pointer to an `int*`. The monstrosity I mention in my comment is specifically a pointer to a 3x3 array of int. Likewise, an `int*` is not a true pointer to a 1D array of ints, it is a pointer to a particular element (the first, if it was obtained by array name decay). Arrays in C and C++ have sizes as part of their type, and "true" pointers to them therefore also have sizes.
Steve Jessop
Ahh, I see. I was not aware that there was an actual "pointer to array of fixed size" type in C++. Thanks for the explanation.
DoctorT
A: 
int a[20][30];
int* b=&a[0][0];
zoli2k
A: 

Original post follows - please disregard, it is misinformed. Leaving it for posterity's sake ;)

However, here is a link I found regarding memory allocation of 2-dimensional arrays in c++. Perhaps it may be of more value.


Not sure it's what you want, and it's been a while since I've written c++, but the reason your cast fails is because you are going from an array of arrays to a pointer of ints. If, on the other hand, you tried from array to array to a pointer of pointers, it would likely work

int tempSec[3][3]; 
int** pTemp = tempSec; 

remember, your array of arrays is really a contiguous block of memory holding pointers to other contiguous blocks of memory - which is why casting an array of arrays to an array of ints will get you an array of what looks like garbage [that garbage is really memory addresses!].

Again, depends on what you want. If you want it in pointer format, pointer of pointers is the way to go. If you want all 9 elements as one contiguous array, you will have to perform a linearization of your double array.

johnny g
"your array of arrays is really a contiguous block of memory holding pointers to other contiguous blocks of memory". No, it really, really isn't.
Steve Jessop
"your array of arrays is really a contiguous block of memory holding pointers"---in this case that is untrue. An array declared `int arr[3][3]` is a contiguous block of memory large enough for 9 `int` s, with access by computed offsets. I think many C programmers assume that all multi-dimensional arrays are pointers-to-pointers (and so on...) because of `char **argv`---but remember that this is an array of `char *`, i.e. an array of strings. In general only "ragged" multidimensional arrays are implemented as multiple layers of indirection (and this is done at the programmer's discretion).
Derrick Turk
@Derrick Turk, thank you for the helpful comments! rustier than i remember ;)
johnny g
Just wanted to add that `int** pTemp = tempSec;` doesn't even compile.
DoctorT
A: 

As Steve pointed out, the proper form is int *pTemp = &tempSec[0][0];. int** pTemp2 = tempSec; does not work. The error given is:

cannot convert 'int (*)[3]' to 'int**' in initialization

It's not stored as an array of pointers to arrays. It's stored as one big vector, and the compiler hides the [a][b] = [a*rowLength+b] from you.

#include <iostream>
using namespace std;
int main()
{
    // Allocate on stack and initialize.
    int tempSec[3][3];
    int n = 0;
    for(int x = 0; x < 3; ++x)
        for(int y = 0; y < 3; ++y)
            tempSec[x][y] = n++;

    // Print some addresses.
    cout << "Array base: " << size_t(tempSec) << endl;
    for(int x = 0; x < 3; ++x)
        cout << "Row " << x << " base: " << size_t(tempSec[x]) << endl;

    // Print contents.
    cout << "As a 1-D vector:" << endl;
    int *pTemp = &tempSec[0][0];
    for(int k = 0; k < 9; ++k)
        cout << "pTemp[" << k << "] = " << pTemp[k] << endl;
    return 0;
}

Output:

Array base: 140734799802384
Row 0 base: 140734799802384
Row 1 base: 140734799802396
Row 2 base: 140734799802408
As a 1-D vector:
pTemp[0] = 0
pTemp[1] = 1
pTemp[2] = 2
pTemp[3] = 3
pTemp[4] = 4
pTemp[5] = 5
pTemp[6] = 6
pTemp[7] = 7
pTemp[8] = 8

Note that the Row 0 address is the same as the full array address, and consecutive rows are offset by sizeof(int) * 3 = 12.

Mike DeSimone
+6  A: 

Its easyier to use a typedef

typedef int  ThreeArray[3];
typedef int  ThreeByThree[3][3];

int main(int argc, char* argv[])
{
    int         data[3][3];

    ThreeArray* dPoint    = data;
    dPoint[0][2]          = 5;
    dPoint[2][1]          = 6;   

    // Doing it without the typedef makes the syntax very hard to read.
    //
    int(*xxPointer)[3]    = data;
    xxPointer[0][1]       = 7;

    // Building a pointer to a three by Three array directly.
    //
    ThreeByThree*  p1     = &data;
    (*p1)[1][2]           = 10;

    // Building a pointer to a three by Three array directly (without typedef)
    //
    int(*p2)[3][3]        = &data;
    (*p2)[1][2]           = 11;

    // Building a reference to a 3 by 3 array.
    //
    ThreeByThree&  ref1   = data;
    ref1[0][0]            = 8;

    // Building a reference to a 3 by 3 array (Without the typedef)
    //
    int(&ref2)[3][3]      = data;
    ref2[1][1]            = 9;


    return 0;
}
Martin York
This discards one of the dimensions of the array, which is exactly what you pointed out on my answer. So now I'm confused what you were on about.
Steve Jessop
@Steve Jessop: You discard both dimensions. I only discard one. Converting to a pointer you are going to loose one dimension you can't help that. If we converted to a reference then you don't need to loose a dimension.
Martin York
In addition to the first line of my answer, I gave the same answer as you, but without the typedef. Anyway, you *can* avoid losing any dimensions, by including all of them in the type of the pointer. It's unlikely that's what the questioner wants, but it's utterly unclear to me whether the questioner specifically wants an `int*`, or just wants some kind of pointer to an array. That's why I mentioned both.
Steve Jessop
@Steve Jessop: Got me there. Added the versions that point directly at 3x3 arrays without loosing type information.
Martin York
+1 for mentioning references too.
Steve Jessop
A: 

Another way to go about doing this, is to first create an array of pointers:

int* pa[3] = { temp[0], temp[1], temp[2] };

Then create a pointer pointer to point to that:

int** pp = pa;

You can then use normal array syntax on that pointer pointer to get the element you're looking for:

int x = pp[1][0]; // gets the first element of the second array

Also, if the only reason you're trying to convert it to a pointer is so you can pass it to a function, you can do this:

void f(int v[3][3]);

As long as the size of the arrays are fixed, you can pass a two-dimensional array to a function like this. It's much more specific than passing a pointer.

DoctorT
Doesn't that signature for `f` actually discard one of the dimensions? It's synonymous with `void f(int (*v)[3]);`, actually a pointer-to-array rather than an array of arrays. So while it is more specific than just passing an `int**`, it's not as specific as you might think. It's a bit misleading to put a number in the last dimension, since the compiler ignores it, but it is a clue to the caller how big an array they're expected to pass.
Steve Jessop
Where by last dimension, of course I mean first dimension...
Steve Jessop
Obviously the compiler will let you do all kinds of crazy things without complaining. And yeah, my point was that this would be much more clear to the user.
DoctorT
+3  A: 

Oh. That's easy!

int aai[3][3];
int* pi = reinterpret_cast<int*>(aai);

You can actually use this awesome technique to cast it into other wonderful types. For example:

int aai[3][3];
int (__stdcall *pfi_lds)(long, double, char*) = reinterpret_cast<int (__stdcall *)(long, double, char*)>(aai);

Isn't that just swell? The question is whether it's meaningful.

You're asking how to lie to your compiler. So the first thing to know is: Why do you want to lie?

conio
Yeah, that's really not a good idea...
DoctorT
Why would you do this? It is perfectly legal to get the address of the first member.
Martin York
A: 

Let's ask cdecl.org to translate your declaration for us:

int tempSec[3][3]

returns

declare tempSec as array 3 of array 3 of int 


Ok, so how do we create a pointer to that? Let's ask cdecl again:

declare pTemp as pointer to array 3 of array 3 of int

returns

int (*pTemp)[3][3]


Since we already have the array 3 of array 3 of int, we can just do:

int (*pTemp)[3][3] = &tempSec;
JRL
A: 
int tempSec[3][3];

int* pTemp = tempSec[0];
FredOverflow