malloc() und calloc() haben einen recht großen Overhead, was RAM und Flash-Verbrauch angeht. Immerhin muss eine Liste der allokierten Blöcke verwaltet werden, und das frisst RAM. Ausserdem führen aufeinander folgende malloc/free Zyklen zu einer Speicherfragmentierung, so daß evtl kein passender Block mehr verfügbar ist.
Seltsamerweise kennt avr-gcc kein alloca(), aber so geht's:
Code:
#include <stdlib.h>

void foo (unsigned short nbytes)
{
	unsigned short i;
	unsigned char *buf;
	
	buf = (unsigned char*) __builtin_alloca ((size_t) nbytes);
	
	for (i=0; i < nbytes; i++)
		buf[i] = 0;
}
Synopsis:
void* __builtin_alloca (size_t nbytes);

__builtin_alloca() ist keine libc-Funktion wie malloc() und calloc(), sondern ein Builtin von GCC.
Der Speicherplatz wird auf dem Stapel angelegt, indem einfach der Stackpointer entsprechend angepasst wird:
Code:
	.text
.global	foo
	.type	foo, @function
foo:
/* prologue: frame size=0 */
	push r28
	push r29
	in r28,__SP_L__
	in r29,__SP_H__
/* prologue end (size=4) */
	in r20,__SP_L__	 ;  tmp47	 ;  41	*movhi/7	[length = 2]
	in r21,__SP_H__	 ;  tmp47
	in r18,__SP_L__	 ; 	 ;  76	*movhi/7	[length = 2]
	in r19,__SP_H__	 ; 
	sub r18,r24	 ; , nbytes	 ;  11	subhi3/1	[length = 2]
	sbc r19,r25	 ; , nbytes
	in __tmp_reg__,__SREG__	 ;  77	*movhi/6	[length = 5]
	cli
	out __SP_H__,r19	 ; 
	out __SREG__,__tmp_reg__
	out __SP_L__,r18	 ; 
	subi r18,lo8(-(1))	 ;  buf,	 ;  12	*addhi3/4	[length = 2]
	sbci r19,hi8(-(1))	 ;  buf,
	sbiw r24,0	 ;  nbytes	 ;  52	tsthi/1	[length = 1]
	breq .L7	 ; ,	 ;  53	branch	[length = 1]
	movw r30,r18	 ;  buf, buf	 ;  68	*movhi/1	[length = 1]
.L5:
	st Z+,__zero_reg__	 ; ,	 ;  25	*movqi/3	[length = 1]
	sbiw r24,1	 ;  i,	 ;  70	*addhi3/3	[length = 1]
	brne .L5	 ; ,	 ;  72	branch	[length = 1]
.L7:
	in __tmp_reg__,__SREG__	 ;  44	*movhi/6	[length = 5]
	cli
	out __SP_H__,r21	 ;  tmp47
	out __SREG__,__tmp_reg__
	out __SP_L__,r20	 ;  tmp47
/* epilogue: frame size=0 */
	pop r29
	pop r28
	ret
Vom Overhead ist so was optimal, allerdings ist das Bereich nicht vorinitialisiert und muss auch nicht freigegeben werden, das geschieht am Ende des C-Blocks automatisch. Der Bereich ist daher nur innerhalb des Blocks gültig, der ihn beschafft hat. Mit return einen Zeiger auf den Bereich rausliefern ist also nicht.
...und ein Laufzeit-Check ob der Platz noch ausreicht scheints auch nicht zu geben, evtl kann man das selber erledigen.
Mit gcc-Option -fstack-check wird anderer Code generiert, vielleicht tut's die ja schon...?

::Edit::
...und ANSI-C ist alloca() auch nicht, sondern GNU-C.
avr-gcc -ansi ...
wird das also anmeckern, sollte zumindest.