views:

132

answers:

3

Please, look at the following code that just convert an unsigned int to a string (there may be some unhandled cases but it's not my question), allocating a char array in the heap and returning it, leaving the user the responsibility to free it after the use. Can you explain me why such function (and others similar) do not exist in C standard library? Yes, printf("%s\n", itos(5)) is a memory leak, but this programming pattern is already used and is consider a good practice[1]. IMO, if such functions had existed since the dawn of C we would had little memory leaks more but tons of buffer overflows less!

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

char* itos(unsigned int value)
{
    int string_l = (value == 0) ? 1 : (int)log10(value) + 1;
    char *string = malloc((string_l + 1) * sizeof(char));
    int residual = value;
    int it;
    for (it = string_l - 1; it >= 0; it--) {
        int digit;
        digit = residual % 10;
        residual = residual / 10;
        string[it] = '0' + digit;
    }
    string[string_l] = '\0';
    return string;
}

int main(void)
{
    char* string = itos(534534345);
    printf("%s\n", string);
    free(string);
    return 0;
}

[1] http://www.opengroup.org/onlinepubs/009695399/functions/getaddrinfo.html

EDIT:

WTH! Habbie did it!

char *string;
asprintf(&string, "%d", 155);
printf("%s\n", string);
free(string);

That's the answer! There's still hope in C! :D

Thanks Habbie!

+1  A: 

In my eyes, memory management is up to the caller, not the callee. For instance, when I'm not using the standard malloc() implementation throughout my program I would be very upset about having to find and call the corresponding free(), the upshot is I wouldn't use such a function.

Edit: Your getaddrinfo() example is perfect, they provide both getaddrinfo() and freeaddrinfo(), that's the only way to make sure I'm calling the right free().

hroptatyr
Just think of what happens type `MyObject *obj = new MyObject();` in c++, that's not garbage collected (as of c++98). There's an agreement between you and the constructor. The constructor tells you: "ok, I will allocate, and destructor will deallocate for you, but it's up to you to decide when to do it". Yeah, there's not a single `free()` like `delete`, and that's a problem. But strictly speaking about the integer->string conversion, the standard `free()` perfectly works for char array.
ceztko
and it's up to me to decide when I call `new MyObject();` so it's *me* who initiates the allocation, and consequently it should be *me* who calls `delete`.
hroptatyr
Ok, true. Anyway, Habbie pointed about `asprintf()` that is exactly what I was looking for, so we can be both happy. :)
ceztko
A: 

Programming has evolved since it was created - this is simply something that wasn't present since the dawn of C, but has evolved in other languages since. I particularly like the way objective-c handles this by returning a string object which has been autoreleased (meaning it will be automatically freed later on, after the object has gone out of scope). You could implement something similar in C if you wanted to:

  1. create a pool for temporary allocations outside your main loop
  2. allocate from the pool as needed using your own allocation function
  3. periodically free the pool at a shallow level in your call stack (for example once per cycle in your very outer main loop)

Another way to achieve the same thing, but allowing you to use system functions that use malloc to allocate memory:

  1. outside your main loop create a list (initially empty) of 'to-be-freed' objects
  2. write a function called 'autofree' that adds pointers to the list and returns the pointer
  3. whenever you need to use it like this: printf("%s\n", autofree(itos(5)));
  4. each time round your main loop, free all the pointers in the list and empty the list

If you do this in a nice way, you can create multiple such autofree pools and nest them around inner loops that potentially create lots of allocations that you want to be freed sooner rather than back in your main loop.

jhabbott
A: 

turns out asprintf is what you need :)

Habbie