Here's a more illustrative example:
#include <iostream>
using namespace std;
int main() {
    int a[2][3] = { {4, 3, 7}, {2, 6, 9} };
    int * b = (int *)a + 4;
    cout << *b << endl; // output is 6
    int c[2 * 3] = { 4, 3, 7, 2, 6, 9 };
    int * d = c + 4;
    cout << *d << endl; // output is 6
}
b and d are both pointers to ints. They are pointing to the base of their respective arrays plus four. With both double- and single-dimensional arrays, this is the memory corresponding to '6'.
It's that C/C++ is doing the math of 2 * 3 behind your back, and allocating space on the stack of 6 * sizeof(int) (ignoring padding). So the pointer arithmetic works out the same.
I'm guessing you ran in to trouble with something like:
        int * b = a + 4;
star.cpp:7:15: error: cannot initialize a variable of type 'int *' with an rvalue of type 'int (*)[3]'
        int * b = a + 4;
              ^   ~~~~~
1 error generated.
Which led you try the int ** b. This isn't a pointer to an int in a double-dimensional array, it's a pointer to a pointer to an int.
Not really sure what the goal is, but a much simpler implementation would be:
    #include <iostream>
    using namespace std;
    int main() {
        int a[2][3] = { {4, 3, 7}, {2, 6, 9} };
        int b = a[1][1];
        cout << b << endl; // output is 6
    }