int (*ap3)[900000] = malloc(sizeof *ap3);
int *a = malloc(900000 * sizeof *a);
int (*arr)[n][m] = malloc(sizeof *arr);
(*arr)[i][j]
int (*arr)[m] = malloc(n*sizeof(*arr));
arr[i][j]
The goal is to have a pointer to the array, and not a pointer to the first element of the array.
Whether this is "nicer" or not, and whether this is what you need in your application, are out of the scope of the fine article.