All of that is true. Before you start using multi-arrays, I'd advise you to make sure you know exactly how parameter passing to functions work, and exactly how dynamic memory allocation works.
Next thing you must be aware of is that multi-arrays in C is
an abstract programming structure and not a mathematical vector/matrix. Unless of course, you specify it that way when you create them.
To make things even more complicated and confusing, C supports many many ways to implement 2-d arrays. They all come with various advantages and disadvantages. You need to pick the one that suits your needs best.
Static multi-array:
int array[x][y];
Advantages: Fast, safe, compatible with ISO functions like memcpy().
Disadvantages: Dimensions can't be set or changed in runtime. Possibly eats a lot of static memory.
Static mangled multi-array:
int array[x*y];
Advantages: Safe, uncomplicated, compatible with ISO functions like memcpy(). Compatible with 1-d arrays and functions accepting 1-d arrays.
Disadvantages: Dimensions can't be set or changed in runtime. Possibly eats a lot of static memory. Somewhat slow access time since the index
needs to be calculated.
Dynamic pointer-to-pointer multi-array:
int** array;
array = malloc(x * sizeof(int*));
for(...) array[i] = malloc(y * sizeof(int));
Advantages: Dimensions can be set and changed in runtime. Easy to change the size of the outer dimension. Allocated on the heap.
Disadvantages: Slow and unsafe. Not compatible with ISO functions like memcpy(), or with static multi-arrays.
Dynamic array pointer multi-array:
int (*array)[x];
for(...) array[i] = malloc(x * sizeof(int));
Advantages: Dimensions can be set and changed in runtime. Easy to change the size of the outer dimension. Allocated on the heap. Compatible with ISO functions like memcpy() and with static multi-arrays.
Disadvantages: Slow and unsafe. Complicated syntax. Turns messy when more than 2 dimensions are used.
(As you can see, this version beats pointer-to-pointer in every way.)
Dynamic mangled multi-array:
int* array;
array = malloc(x*y);
Advantages: Dimensions can be set and changed in runtime. Allocated on the heap. Compatible with ISO functions like memcpy() and with static multi-arrays.
Disadvantages: Slow and unsafe. Changing dimensions is inefficient.