Truly multidimensional arrays in technicolor

When I searched around, looking to learn how to do a REAL multi-dimensional array, because I needed one as a constant, I can’t seem to find anywhere, where anyone tackles anything beyond two elements. So I just kind of figured it out, and I felt that I needed to write this up so that someone somewhere down the line, who finds themselves in this position can see by clear example, how to dimension AND populate an array of ANY size elements with relative ease.

Starting with the simple binary two dimensional array - and I’m using INT here because it’s easy to see plainly, but it doesn’t matter what the datatype is, the array arrangement will be the same, it’s only the information inside the array that will be different, like for Strings, you would have double quotes and characters inside those quotes between the comma’s where I simply have x,y,z because I’m trying to keep it simple and obvious.

      myArray[3][3] = {
					            {a,b,c},
					            {d,e,f},
					            {g,h,i},
				             };

Obvious, right? Three rows of three and you would address each row like this

:[0][0],[0][1],[0][2],
 [1][0],[1][1],[1][2],
 [2][0],[2][1],[2][2],


[center]ex: myArray[1][1]=e; myArray[2][0]=g;[/center]

Make sense?  But what if I needed 4 rows of 5?

[tt]        myArray[4][5] = {
					           {a,b,c,d,e},
					           {f,g,h,i,j},			ex: myArray[2][3]=n;  myArray[3][2]=r;
					           {k,l,m,n,o},
					           {p,q,r,s,t},
				            };

Easy, right? But what happens if we go even further with this? Let’s try a 3 element array:

    myArray[5][2][3] = {
						        {{x,y,z}, {x,y,z}},
						        {{x,y,z}, {x,y,z}},
						        {{x,y,z}, {x,y,z}},  ex: myArray[2][2][0]=x (third row, left x)
						        {{x,y,z}, {x,y,z}},
						        {{x,y,z}, {x,y,z}},
					        };

Can you see how the brackets define each element? Let me see if I can make it clearer:

{ ← Outside bracket always contains the element on the left [5] in this case
{ ← Next element
{ ← final element

Let me show you that again, but with the brackets colored to match the array declaration:

myArray[color=red][5][/color][color=green][2][/color][color=blue][3][/color] = [color=red]{[/color]
						[color=green]{[/color][color=blue]{[/color]a,b,c[color=blue]}[/color],  [color=blue]{[/color]d,e,f[color=blue]}[/color][color=green]}[/color],
						[color=green]{[/color][color=blue]{[/color]g,h,i[color=blue]}[/color],  [color=blue]{[/color]j,k,l[color=blue]}[/color][color=green]}[/color],
						[color=green]{[/color][color=blue]{[/color]m,n,o[color=blue]}[/color],  [color=blue]{[/color]p,q,r[color=blue]}[/color][color=green]}[/color],  ex: myArray[2][1][0]=  j;  
						[color=green]{[/color][color=blue]{[/color]s,t,u[color=blue]}[/color],  [color=blue]{[/color]v,w,x[color=blue]}[/color][color=green]}[/color],      myArray[4][0][3]= aa;
						[color=green]{[/color][color=blue]{[/color]y,z,aa[color=blue]}[/color], [color=blue]{[/color]bb,cc,dd[color=blue]}[/color][color=green]}[/color],
					    [color=red]}[/color];

Can you see how the groupings match the elements? 5 rows bracketed in RED.

Within each of those 5 rows, we have TWO sets of brackets separated by a comma.

Then within each of those two elements, we have our final three numbers

Now let’s go into something even deeper - this is a real structure that I use to define motor speeds for a given length of time. A method cycles through the different sets of data and uses the first two integers as motor values than the third integer as a delay time … to make some motors do specific things.

const int motorSettings[6][2][5][3] =
{
{{{x,y,z},{x,y,z},{x,y,z},{x,y,z},{x,y,z}}, {{x,y,z},{x,y,z},{x,y,z},{x,y,z},{x,y,z}}},
{{{x,y,z},{x,y,z},{x,y,z},{x,y,z},{x,y,z}}, {{x,y,z},{x,y,z},{x,y,z},{x,y,z},{x,y,z}}},
{{{x,y,z},{x,y,z},{x,y,z},{x,y,z},{x,y,z}}, {{x,y,z},{x,y,z},{x,y,z},{x,y,z},{x,y,z}}},
{{{x,y,z},{x,y,z},{x,y,z},{x,y,z},{x,y,z}}, {{x,y,z},{x,y,z},{x,y,z},{x,y,z},{x,y,z}}},
{{{x,y,z},{x,y,z},{x,y,z},{x,y,z},{x,y,z}}, {{x,y,z},{x,y,z},{x,y,z},{x,y,z},{x,y,z}}},
{{{x,y,z},{x,y,z},{x,y,z},{x,y,z},{x,y,z}}, {{x,y,z},{x,y,z},{x,y,z},{x,y,z},{x,y,z}}},
};

Can you see it now? It should be easy to define and populate pretty much any array that you need. It’s not some enigmatic mystery that requires multi-dimensional spacial thought like so many people say…

I hope this helps someone in the future.

Thank you,

Mike Sims

Let's try a 3 element array:

myArray[5][2][3] =

I'm sorry, but what you've got there is a thirty element array.

AWOL:
I'm sorry, but what you've got there is a thirty element array.

Ok ... what's your point? The number of elements is inconsequential. I was merely trying to help people understand HOW to declare, then populate large arrays...

It's like if I were teaching people how to paint boats ... and you raise your hand and say something entirely profound like, "I'm sorry ... but you have a boat right there ..."

... ummmm ..... duh?

You're confusing elements with dimensions . . . duh.

AWOL:
You're confusing elements with dimensions . . . duh.

And yet it works ... I fail to see where I errored

  myArray[5][2][3] =

How many elements are there in this array ?
How many dimensions are there in this array ?

Whilst it may work you are describing it wrongly

When I searched around, looking to learn how to do a REAL multi-dimensional array, because I needed one as a constant, I can't seem to find anywhere

Well you might have searched with improper vocabulary. This is known as aggregate initialization and list initialization

So A couple things you could add

  • the compiler can do size calculation for you if you populate the arrays
    int vector[] = {1,2,3,4}; // compiler will decide you need 4 elements
    Only the "left-most" dimension can have its size left out
int matrix[][3] = {{1,2,3},{4,5,6},{7,8,9}};

This is because the compiler really sees this as a pointer to the start of the data, and so you need to help the compiler understand where the next row starts to perform maths on pointers in memory. the compiler will recursively initialize the array, noting that each subarray starts with a left brace and has no more than the required number of initializers, and will count the number of subarrays to determine the first dimension of the array.

This is described in “The C Programming Language" by K&R

An aggregate is a structure or array. If an aggregate contains members of aggregate type, the initialization rules apply recursively. Braces may be elided in the initialization as follows: if the initializer for an aggregate's member that is itself an aggregate begins with a left brace, then the succeeding comma-separated list of initializers initialize the members of the sub aggregate; it is erroneous for there to be more initializers than members. If, however, the initializer for a subaggregate does not begin with a left brace, then only enough elements from the list are taken to account of the members of the subaggregate; any remaining members are left to initialize the next member of the aggregate of which the subaggregate is a part. For example,

int x = { 1, 3, 5 };
declares and initializes x as a 1-dimensional array with thee members, since no size was specified and there are three initializers.

  • such assignments can be done only when you declare and define the variable, not later in code

UKHeliBob:

  myArray[5][2][3] =

How many elements are there in this array ?
How many dimensions are there in this array ?

Whilst it may work you are describing it wrongly

I suppose it’s possible … I just kinda got this stuff somewhat figured out and am open to error correction.

:slight_smile: