It depends. If you declare an array like this:
int values[m][n];
then the compiler optimizes the accesses, i.e. using a linear piece of memory and computing the right offsets (like in your pseudo code).
But if you declare an array like this:
int **values;
values = new int*[m];
for (size_t i = 0; i < m; ++i) values[i] = new int[n];
Then the compiler can't optimize an array access like
values[row][col]
// same as
*(*(values+row) + col)
I.e. such code yields one extra memory access. And since on current architectures, a memory access is several orders of magnitudes more expensive then computing the offset, this style of more-dimensional arrays is less efficient than using a linear block of memory and computing (or let the compiler compute where possible) the offsets.