All things being equal, allocating memory through malloc (or calloc or realloc) will be both slower and more labor-intensive to manage than using an auto (local) array, which will be slower than using a static array.
All things are typically not equal, though. As you've discovered, a static array doesn't work well when dealing with recursion (or when you just need to preserve multiple states, as anyone who's tried to use strtok to tokenize a string like "a=b&c=d&e=f" knows all too well). A 128K auto array is somewhat on the large side, and if the function is recursive that can be an issue since stack space is typically limited for an individual process.
This is kind of an ideal use case for dynamic memory, which typically isn't as limited as memory on the stack. The trade-off is that it will be slower that the alternatives and will require more work on your part.
Exactly how much slower will depend on how you allocate and use it - allocating it as a single contiguous chunk like so only requires a single malloc (and corresponding free) call and should be better for locality:
char (*tmp)[32768] = malloc( 4 * sizeof *tmp );
if ( tmp )
{
for ( size_t i = 0; i < 4; i++ )
strcpy( tmp[i], some_string ); // or however you intend to use tmp;
...
free( tmp );
}
but if your heap is sufficiently fragmented you may not be able to allocate it as a single contiguous chunk and have to do it piecemeal, using multiple malloc (and free) calls:
char **tmp = malloc( 4 * sizeof *tmp );
if ( tmp )
{
for ( size_t i = 0; i < 4; i++ )
{
tmp[i] = malloc( sizeof *tmp[i] * 32768 );
if ( tmp[i] )
{
strcpy( tmp[i], some_string );
}
}
...
for ( size_t i = 0; i < 4; i++ )
free( tmp[i] );
free( tmp );
}
The only way to know for sure which is faster and works better for your purposes is to code up multiple versions and to measure their performance.
Having said all that...
It doesn't matter how fast your code is if it does the wrong thing, or gives the wrong answer, or vomits all over the floor at the first hint of bad input, or exposes sensitive data, or provides an entry point for malware, or cannot be modified or maintained. Code for correctness and maintainability first, without consideration for raw execution speed, then for all the other issues listed above. Unless you have a hard performance requirement ("This operation must complete within X msec"), don't worry about speed. Get it right first, then if you aren't satisfied you can always tune the performance later.
Also, depending on what the rest of your code does, the deltas between the different methods of allocating and managing that memory may be insignificant - if your code is spending the bulk of its time waiting for someone to type in data, then the extra few clocks spent using malloc as opposed to an auto array really don't matter. On the other hand, if you're calling this code thousands of times in a tight loop, those extra clocks will add up to a significant difference.
Make your decisions based on analysis and measurement, not guesswork.