As a general rule, if you think "wouldn't it be great if XYZ would work and I could make my code cleaner", the answer is: "It does work!"
Here is some code snippet that probably does what you want:
PANEL *pointer_pan[4][31];
void initialize()
{
memset(pointer_pan, 0, 4 * 31 * sizeof(PANEL *));
}
void cleanup()
{
int i, j;
for(i = 0; i < 4; i ++)
{
for(j = 0; j < 31; j ++)
{
if(pointer_pan[i][j])
{
ptr_remove(pointer_pan[i][j]);
pointer_pan[i][j] = NULL;
}
}
}
}
You may want to learn/read up a bit on basic programming and/or read some code written by others with experience.
Note that the memset() trick doesn't work with dynamically allocated multidimensional arrays, because in reality this is still a flat, contiguous block of memory. The compiler will translate the 2D access into a single offset into the memory block.