So after you execute
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
double **m;
p = balance;
m = &p;
the following are all true:
  m == &p                     // double **
 *m ==  p == &balance[0]      // double *
**m == *p ==  balance[0]      // double
(*m)[i] == p[i] == balance[i] // double
Remember that the expression a[i] is defined as *(a + i); given the address a, offset i elements (not bytes1) from that address and dereference the result.   
This means that *p is equivalent to *(p + 0), which is equivalent to p[0].  Thus, you can use p[i] in place of balance[i].  Since *m == p, you can also use (*m)[i] in place of p[i].  The parentheses are necessary - unary * has lower precedence than postfix [], so *m[i] would be parsed as *(m[i]), which is not what you want here.  
You can increment p directly to "walk" through the balance array:
p = balance; // p == &balance[0];
for ( i = 0; i < 5; i++ )
  printf( "%f\n", *p++ );
Each time through the loop, p is incremented to point to the next element of balance.  
You can do something similar with the expression (*m):
p = balance; // p == &balance[0]
m = &p;      
for ( i = 0; i < 5; i++ )
  printf( "%f\n", (*m)++ );
Again, the parentheses around *m are necessary; since postfix ++ has higher precedence than unary *, the expression *m++ would be parsed as *(m++), which is not what we want.  We don't want to change the value of m, we want to change the value of what m points to, which in this case is p.  
Now, suppose we leave p out of the picture completely; can we do something like:
double balance[5] = { ... };
double **m;
*m = balance;
No.  In this example, m is an invalid pointer; it hasn't been initialized to point anywhere meaningful, so *m will invoke undefined behavior (which can include, but is not limited to, a segfault).  m has to point to an object of type double * before you can dereference it.  There has to be a middleman like p in order for that scheme to work.  
- Pointer arithmetic always takes the size of the pointed-to type into account - if apoints to an object of typeT, thena + 1yields the address of the next object of typeT, which may be more than 1 byte away from the current address.