dargaud
dargaud

Reputation: 2571

Returning a string properly in C, multiple times

OK, the following way to return a string works fine:

char* SU(double V) {
    static char Str[80];
    // Do something
    return Str;
}
printf("%s", SU(A));

But the following will fail silently because the string space in memory is the same at the end of both calls:

printf("%s %s", SU(A), SU(B));

How can I do this cleanly and simply ? I was looking at alloca() but I don't think I can return a string allocated with alloca(), can I ?

Upvotes: 0

Views: 212

Answers (5)

dash-o
dash-o

Reputation: 14452

Effectively, all current C compilers support compound literals and inline functions. Together it is possible to write thread-safe, memory-safe implementation that does not rely on static buffers (that can lead to unexpected bugs).

Basic idea is to combined a function that uses caller provided buffer, with a macro to abstract the creation of this temporary buffer. Negligent performance/memory impact for most applications.

For example - for the case of return the string-ified version of the a number the following itoa function can be implemented with macro/wrapper/inline function.

The limitation is that the wrapper need a way to estimate the size of returned string.

#include <stdio.h>

const char *itoa_wrapper(char *buffer, int buffer_sz, int val)
{
        int result = snprintf(buffer, buffer_sz, "%d", val) ;
                // Assuming formatting always works
        return buffer ;
}


#define itoa(val) itoa_wrapper( (char[20]) {}, 20, val)

int main(int argc, char **argv)
{
        printf("ARGC=%s, 1+2+3+4=%s\n", itoa(argc), itoa(1+2+3+4)) ;
}

Upvotes: 1

dargaud
dargaud

Reputation: 2571

In addition to the perfectly valid solutions you have proposed, I thought about a different approach which can be applied in this case, since the objective was to feed the returned strings to printf: it's to use the GNU C register_printf_function function to add custom format strings to printf.

More info here and an example here for MAC addresses

Upvotes: 0

AndersK
AndersK

Reputation: 36082

Change your function to allocate a string on the heap instead.

char* SU(double V) {
    char* Str = malloc(80);
    // Do something
    return Str;
}

don't forget to free the returned string once you are done with it.

char* a = SU(A);
char* b = SU(B);
printf("%s %s", a, b);
free(b);
free(a);

Upvotes: 1

Lundin
Lundin

Reputation: 213872

It is always best to leave allocation to the caller. The standard way to return strings from functions in C is through parameter:

void SU (double V, char* str, size_t size);

Or in modern C you could do:

void SU (double V, size_t size, char str[static size]); 

(See this)

Upvotes: 3

Michael F
Michael F

Reputation: 40829

Serialise the calls to SU:

printf("%s ", SU(A));
printf("%s" , SU(B));

Alternatively, copy the returned strings:

char *sua = strdup(SU(A));
char *sub = strdup(SU(B));
printf("%s %s", sua, sub);
free(sua);
free(sub);

Upvotes: 2

Related Questions