There are two problems. First, indeed, you are confused about pointers/arrays:
int a[4]; // this is an array of 4 integers, a is the name of the array
int *a[4]; // This is an array of 4 *pointers* to int
So your declaration:
int **blah[4];
Define an array of 4 pointers to pointers array. Maybe you are confused by the following fact (I know I was when I learned C). If you declare a variable:
int *a;
This is a declaration of a pointer to an integer. But if you have a variable a which is a pointer, you get the thing it points to (an integer here) by using *a:
*a = 1; // a is a pointer (i.e. an address), *a is the value pointed to by a.
So * in declaration is used to declare pointer, but * in statements is used to deference value.
But your second problem has nothing to do with pointer per-se. It is about ressource-management (memory being one, but file, locks being others). Anything allocated on the stack does not exist anymore when it is out of scope. In pure C, you only really have one solution: allocating on the heap with malloc, and making sure to free afterwards. So you would do something like:
// foo is a struct
foo *init_foo()
{
foo* tmp;
tmp = malloc(sizeof(*tmp));
// initialize tmp
return tmp;
}
And then, you will clean it with another function:
foo *a;
a = init_foo();
// do stuff
clean_foo(a);
Example: the FILE* handle and fopen/fclose (in addition to allocating stuff, there are some things related to the OS to handle the file). Another solution is to use alloca, which is not standard C, but is supported by many toolchains.
In C++, you can use smart pointers, which use for example reference counting to do resources management. I am less familiar with C++, and I am sure people will jump in on that part. The idea with reference counting is that it still gives some of the advantages of auto pointers (you don't have to call delete by yourself, which is extremely error-prone for non trivial projects), but without being purely scope-based. One reference counting-based smart pointer is shared_ptr in boost.