Say you have a C function called profile which allocates and returns a string, expecting you to free it. The main return value is an int, the string pointer is returned by reference in a char** argument. You may use let-location to easily handle the returned string, if you follow the recipe below.
; int profile(const char *in, char **out); (define profile (foreign-lambda int "profile" (const c-string) (pointer c-string))) (let-location ((out c-string*)) (let ((rv (profile "LAMBDA-CALCULUS.ORG" (location out)))) (let ((out out)) ; clean up out (if (eqv? rv 0) (print out) (error "profile error" rv)))))
It's fine to use let-location with a c-string type. Internally, every time you dereference this type, Chicken calls ##sys#peek-c-string, which creates a new scheme string and copies the C string in with strcpy().
However, is it safe to use a c-string* type to get its automatic free() behavior? Yes, if you're careful.
Chicken will call ##sys#peek-and-free-c-string every time your location (out) is dereferenced. This does a strcpy() plus a free(). So, it is not safe to dereference out more than once during the flow of control, as it will cause a double-free and, worse, a reference to freed memory. This also implies that if you do not refer to out at all, its memory will leak.
A safe way to handle this situation is to bind all location variables to themselves in a surrounding let statement, which guarantees the free occurs exactly once. It is safe to dereference c-string* locations even if they are NULL, as it will just return #f without calling free().
Of course, you may instead structure your code so you're sure the location is always dereferenced exactly once, when not NULL. This happens to be true in the simple example above, in fact. On the other hand, it is easy to accidentally violate this requirement, and the special behavior of out may not be apparent to readers of your code.
This technique is also applicable for regular c-string locations that you use more than once, to avoid redundant strcpy() calls.