A question about multidimensional arrays

Hello,
I have some questions about multidimensional arrays in the Rust-Lang, and please answer my questions briefly.
A two Dimensional Array in C++ is as follow:

int arr[4][2] = {
{0, 0},
{0, 0},
{0, 0},
{0, 0}
} ;

In Rust-Lang, it is something like let mut x = [[0; N] ; M];. My questions are:

1- What are N and M? Is M row and N column?
2- Why arrays must be initialized and why following syntax are wrong?

let mut x=[[0;4];[0;4]];
let mut x=[[4];4];

3- The following line initialized all items of an array to zero, but how can I initialize only rows or columns with zero?

let mut x=[[0;4];4];

4- I want to print the contents of all rows and columns, which lines of the following code is wrong?

fn main() {
let mut x=[[0;4];4];
    for i in 0..3 {
        for j in 0..i {
         println!("{}",x[i][j]);
        }
    }
}

Thank you.

Arrays don't have an intrinsic orientation, they are just bits in memory. What you consider rows and columns is merely a convention.

For exactly the same reason as variables of every other type must be.

I mean, because the language is defined like so? You should read the relevant documentation for language features instead of trying to guess how they are defined.

I don't understand that. What do you mean by initializing only rows or columns? If you initialize all rows (or equivalently, all columns) of the array, then you initialized all of it to all 0s.

This smells like homework? But anyway, you don't want j to run from 0 to i, because that only prints a triangular half of the array, above/below the diagonal. If you want to print all 16 elements, then you need both indices to run from 0 to 4.

3 Likes

N and M are the dimensions of the array, which is indexed like x[m][n]. Whether you consider the inner dimension N to be the width or height is a matter of perspective, and Rust doesn't really care which one you use.

In safe Rust, you (mostly) can't have partially initialized types, and this includes arrays. If you want to have some initialized and some uninitialized elements, you'll have to use something like MaybeUninit.

Rust only has language support for one-dimensional arrays, so a two-dimensional array is really just an array of arrays. An array literal looks like [value;count]¹, where value is an expression that evaluates to the element type. When that element type is also an array, this syntax turns into the [[value;inner_count];outer_count] syntax that you use later.

@H2CO3 has already identified the core problem with the code you've written, but you might want to consider a less error-prone approach than looping over the array indices:

for (_j, inner) in x.iter().enumerate() {
    for (_i, element) in inner.iter().enumerate() {
        println("{element}");
    }
}

¹ Not a complete description

3 Likes

Hello,
Thank you so much for your reply.
No, this is not homework. I have started to learn Rust-Lang, and these are the questions that have arisen for me.

Hello,
Thank you so much for your reply.
Why x=[[0;4];[0;4]] is wrong? It could initialize all rows and columns to zero.
About the number 4, in C++ you can use the following code to initialize all items of an array to zero:

for (int i = 0; i < ROW; i++)
  for (int j = 0; j < COLUMN; j++)
    array[i][j] = 0;

And:

fn main() {
let mut x=[[0;4];4];
    for i in 0..3 {
        for j in 0..i {
         println!("{}",x[i][j]);
        }
    }
}

It will:

i=0
x[0][0]

i=1
x[0][0]
x[0][1]

And so on. Am I right?

Please consider let mut x = [[[0; 4]; 8]; 15];, why the last item is x[14][7][3] not x[3][7][14] ?

Because the syntax for array initialization is [value; length], and [0; 4] is not a length.

There are still no multi-dimensional arrays built into the language.

2 Likes

This works:

fn main() {
    let mut x = [[0; 4], [0; 4]];
    x[0][0] = 10;
    x[0][1] = 20;
    x[0][2] = 30;
    x[0][3] = 40;
    x[1][0] = 50;
    x[1][1] = 60;
    x[1][2] = 70;
    x[1][3] = 80;
    println!("{x:?}");
}

(Playground)

Output:

[[10, 20, 30, 40], [50, 60, 70, 80]]


Alternatively:

-    let mut x = [[0; 4], [0; 4]];
+    let mut x = [[0; 4]; 2];

(Playground)

4 Likes

Let's split this up into two lines:

let initializer = [[0; 4]; 8];
let mut x = [initializer; 15];

So x is an array of length 15. The last element of x is therefore x[14]. x[14] is itself an array whose last element is (x[14])[7] = x[14][7]. That again is an array whose last element is x[14][7][3].

3 Likes

Hello,
Thank you so much for your reply.
I have a little C++ background and the Rust-Lang is new for me. When I write let initializer = [[0; 4]; 8];, then it creates an array with 4 rows and 8 columns and initialized all of its items with zero. Am I right?

Kind of lack.

It's equivalent to:

let a = [0, 0, 0, 0];
let initializer = [a; 8];

So this creates an array of 8 elements, each of which is an array of 4 elements, each of which is the number 0.

Whether you visualize the arrays horizontally or vertically is up to your imagination, they don't have an inherent direction in space, they are just sequences of elements. You can think of it as a row of rows, a column of columns, a row of columns, or a column of rows. It's up to you.

3 Likes

Instead of thinking of it as a multidimensional array, think of it as an array of arrays. That way when seeing [0;N] you know it's an array of length N and when seeing [[0;N];M] you know it's an array of length M containing arrays of length N.

All data in rust must be initialized, unless it's a MaybeUninit type.

Suppose you have a statement let foo = bar[i]. You know that foo will be an element of bar. Now suppose you have another statement following the previous one: let foobar = foo[j]. That would mean foobar is an element of foo. So in a statement let foobar = bar[i][j] you can conclude that foobar is the j'th element of the i'th array.

2 Likes

Hello all,
I just wanted to remind that, in let mut x = [[0.0; N] ; M];, M is rows and N is columns.

Thank you.

Not necessarily. If x is interpreted in column-major order then M is columns; it all depends on the expectation of the libraries you’re using.

The only thing you can say out of context is that M is the major (slowest-changing) axis and that N is the minor (fastest-changing) one.

1 Like

What nobody has mentioned here is "row major order" or "column major order".

An N * M two dimensional array is a contiguous sequence of N * M elements in memory.

But is that N lots of M or M lots of N?

It's important to know when one is traversing the array, should we iterate over columns inside rows or rows inside columns? Important because Conway around is cache friendly and fast, the other way around causes lots of cache misses and is slow.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.