+2  A: 

Have the caller provide the buffer (and the size of the buffer). It's thread safe, and the buffer can usually go on the stack, so you don't bring on the overhead of heap allocation.

Alan
+7  A: 

Well, one widely used approach is to put the responsibility of preparing the memory buffer for the result on the caller. The caller can choose whatever method it likes best.

In your case write your p as

char* p(char *buffer, size_t max_length, int x) { 
  snprintf(buffer, max_length, "number is %d", x); 
  return buffer; 
} 

and call it as

char buffer1[512], buffer2[512];   
some_func( somearg, p(buffer1, sizeof buffer1 - 1, 6), p(buffer2, sizeof buffer2 - 1, 7) );   

This approach has at least one obvious drawback though: in general case the caller does not know in advance how many characters it needs to allocate for the buffer. If a good constant compile-time value is available, then it is easy, but in more complicated cases an additional effort is required, like providing some kind of "pre-calculation" functionality that returns the required buffer size as a run-time value. (The snprintf function actually works that way: you can call it with null buffer pointer and zero buffer size, just to make a fictive run in order to determine the buffer size).

AndreyT
A: 

In short, no. C does not provide any form of automatic heap management, so you're own for tracking allocated memory. A standard C-like solution is to have the caller provide a buffer, instead of allocating one internally. Although this just moves the responsibility of tracking memory around, it often ends up in a more convenient place. You could, I suppose, look in to Boehm's conservative garbage collector if you want to get a form of garbage collection in C.

Dale Hagglund
+2  A: 

So long as you understand this to be thread-unsafe and so long that your logic expect the values returned by the "convenience" methods to only be valid for the duration of a few calls to [possibly various] methods, you can maybe extend this convenience in two unrelated and possibly complementary ways.

  • Add an extra argument to the convenience methods so these can pass -optionally- a container for the return value (also add a size_of_passed_buffer argument if such size cannot be implicitly set). Whenever the caller supplies a buffer, use it, otherwise, use the static buffer.
    BTW, if the buffer passed to the convenience methods are local variables, their allocation will be automatically (and adequately) managed, following the lifespan of the subroutines where the convenience methods are called.

  • Use a circular buffer, allowing for a given number of calls before the buffer elements are reused.
    Such a buffer can also be global, i.e. shared with multiple "convenience" methods (which of course also need to a) play nice, thread-wise, and b) share the pointer to next available byte/element in buffer.


Implementing all this may seem to be

  • a lot of work (for the convenience logic), and also
  • a potential for several bugs/issues

However, provided that

  • the buffer(s) is (are) adequately sized, and that
  • the logic using these convenience methods understand the "rules of the game",

this pattern supplies a simplistic automated heap management system, which is a nice thing to have in C (which unlike with Java, .NET and other systems does not offer a built in GC-based heap management)

mjv
That sounds appropriate if the data had to persist through several interface returns and callbacks, and overhead were really crucial and requirements set, such as in a real-time driver. But what's the advantage over the caller allocating a buffer on the stack? This is just asking for a buffer overflow.
Potatoswatter
Interesting approach. It would provide the oh-so-sought convenience at the cost of implementing this with its inherint dangers (hopefully only once) ;)
joveha
A: 

If the args to the helpers are always literals (as in the example), you could use a macro:

#define P(NUMLIT) ("number is " #NUMLIT)

...
somefunc(somearg, P(6), P(7));
...

The preprocessor creates a string from the macro argument NUMLIT and appends it to "number is " to create a single string literal, just as

"this" " " "string" 

is emitted as a single string literal, "this string".

Tim Schaeffer
A: 

I found an alternate method. Something like this:

#define INIT(n) \
 int xi = 0; \
 char *x[n]; \

#define MACRO(s) \
 (++xi, xi %= sizeof(x)/sizeof(*x), x[xi] = alloca(strlen(s)+1), strcpy(x[xi], (s)), x[xi])

that I can call like this:

INIT(2);
some_func( somearg, MACRO("testing1"), MACRO("testing2"));

So the buffers are on the stack without needing any freeing. And it's even thread-safe.

joveha
I've shamelessly made this the correct answer until somebody comes in here and challenges it :)
joveha