The first line declares a pointer to a pointer called memo. What this means is that you have a pointer (*), where the element that it points to is of type int*.
When you get to the second line, you are dynamically allocating an array of int*'s, of size rows. In memory, this looks like this (assuming rows is 3):
1 2
//memo
//[int**] --------->[int*][int*][int*]
Notice that memo is pointing to the first element of the array, or the first int* in the array of 3 int*'s. A pointer to an array will always work like this. It always points to the first element. You can get the other elements by using the bracket notation and moving the pointer.
Thus, a for loop is used to move through each element of the array (remember, each element is an int*) and allocate a new array of 3 ints for each pointer. Each int* after this operation will point to the first element of another array. after the for loop, it looks sort of like this.
Thus, you are left with a 3x3 array. When you access it, you must first choose which int* in the first array you want (the columns), then you choose which int of the array that int* points to you want (row).
int **a = newint*[rows]; // allocate row pointers
a[0] = newint[rows * cols]; // allocate data
for (int r = 1; r < rows; ++r) // set row pointers
a[r] = a[r - 1] + cols;
// fill
for (int r = 0; r < rows; ++r)
for (int c = 0; c < cols; ++c)
a[r][c] = (r+1) * (c+1);
" a[0] = new int[rows * cols];"
Here, we're creating a row with the capacity of rows * cols. How does that help?
" a[r] = a[r - 1] + cols;"
Why are we adding the number of cols to an element in the array a[r]?
How does that help?
it puts all your data in one solid block. that means you can choose to iterate it directly, with a 1-d for loop, instead of a 2-d for loop, which depending on what you are doing is often useful. Its a triple whammy to do it the other way: you pay for nested loops (2 conditional checks, 2 variable increments, etc), you pay for page faults (data isnt a solid block), and you pay for indexing (its more internal math to index 2-d than 1-d). You won't notice the speed on today's bajillion ops per second, until you need something in a hurry or have something huge.
It also lets you reshape the data, eg at 100 item can be 1x100, 2x50, 10x10, etc. You can't do that with non solid blocks. It lets you memcpy, or .write(), etc without any issues, and more efficiently. And these are just a few examples. Most of what you can do better with 1 block you can do with 2, its just faster. In a few places, though, you can't do it at all without a data copy that was not necessary or jumping thru hoops. The read/write ability alone is pure gold as file read/write are often bottlenecks.
that addition is not data, its pointers. reread that line of code until you understand that this is pointer math, not data!! What ie is doing is giving you a big block of values...
0,1,2,3,4,5,6,7,8,9,...
lets say you want to break that into a 2x5...
your first row pointer is a 0, your second is at 5. cols is 5. so the pointer+0 and the pointer+5 give you the row pointers that break it into 2-d. You are just taking addresses in the right spots to make it look like 2-d, and can be indexed etc 2-d, but its still one nice 1-d block when you need that capability.
You are not dumb, pointers take a bit to fully understand. We all went thru it.