0

free() only needs the pointer value to release allocated memory. Which means that C knows how big assigned memory blocks are. Then how come there isn't some built-in function to find the size of a pointer array?

I know the convention is to keep track of array sizes, but given that there already is some memory management happening natively, why don't we harness that to have a convenient size() function for arrays?

hazrmard
  • 3,397
  • 4
  • 22
  • 36
  • 2
    Because nobody has designed and proposed such a feature. I expect there would be implementability concerns. But think also that not every pointer is the result of `malloc`, and so you would have an undiagnosable precondition. – Kerrek SB Jul 22 '16 at 00:03
  • 1
    Related: http://stackoverflow.com/q/18570362/827263 – Keith Thompson Jul 22 '16 at 00:03
  • @KerrekSB: I believe such a feature exists in some non-standard extensions. One question: do you want the size requested, or the size actually allocated? (Note that `sizeof` is an operator, not a function.) – Keith Thompson Jul 22 '16 at 00:05
  • 1
    `sizeof` is a compile time feature. `free` is a runtime function. – Daniel A. White Jul 22 '16 at 00:05
  • @DanielA.White: What about `sizeof (VLA)`? – EOF Jul 22 '16 at 00:07
  • @EOF http://stackoverflow.com/questions/14995870/behavior-of-sizeof-on-variable-length-arrays-c-only – Daniel A. White Jul 22 '16 at 00:08
  • I think @KerrekSB has a nice point, not all poitners point to `malloc()`ed memory. More importantly, not all pointers point to arrays, and such a feature would have to distinguish between pointers that point to arrays and pointers that don't. So it's not possible to implement it. – Iharob Al Asimi Jul 22 '16 at 00:09
  • @EOF: Still an operator. In that case, it happens to invoke run-time code (as most operators usually do). – Keith Thompson Jul 22 '16 at 00:09
  • @iharob: It would be plausible to have a `malloc_size()` function that has undefined behavior for an argument that wasn't allocated by `malloc` or equivalent (just as `free()` does). But requiring such a function would impose overhead on implementations. – Keith Thompson Jul 22 '16 at 00:10
  • Even if a pointer does not point to a `malloc()`ed array, `free()` still knows how big the memory block is. And even if a pointer is to the stack memory, that still has to be freed after execution exits that variable's scope. In both cases, C knows how much memory to free. Therefore, a `size()` function could be implemented. – hazrmard Jul 22 '16 at 00:20
  • 2
    The feature would be of little use because of rounding, and subdividing. For example, if you `malloc(3)`, most implementations will return 1 block of 16 bytes. The `free` function only knows that the pointer represents 1 block of memory. It doesn't remember that you asked for 3 bytes. On the other hand, you could `malloc(1024)` and then use that memory for 4 arrays of 256 bytes each. There's no way for the proposed `size()` function to know how you subdivided the memory. – user3386109 Jul 22 '16 at 00:21
  • 1
    @hazrmard: For example: `int array1[10]; int array2[20]; int *ptr = rand() % 2 ? array1 : array2;`. There's no way to know how big an array `ptr` points to unless you keep track of it yourself. Can you implement `size()` so that `size(ptr)` returns the correct size? – Keith Thompson Jul 22 '16 at 00:27
  • 1
    @hazrmard "Even if a pointer does not point to a `malloc()`ed array, `free()` still knows how big the memory block is." No it doesn't. In fact, passing a pointer that was not `[m/c/re]alloc()`ed and is not `NULL` to `free()` is *undefined behavior*. – EOF Jul 22 '16 at 00:48

4 Answers4

6

Such a function would be possible. The question is why the C standard doesn't require it.

The GNU C library implementation provides a function malloc_usable_size() that's similar to what you're suggesting. It returns the number of usable bytes for a malloc()ed pointer -- which may be greater than the requested size for various reasons.

It's not 100% clear why no such function is in the standard. It's not mentioned in the 1989 ANSI C Rationale or in the ISO C99 Rationale.

One thing to keep in mind is that an implementation doesn't need to keep track of the number of bytes requested by a malloc() call. It will often round up the request to some larger value, and it only needs to keep track of that.

For that matter, free() doesn't necessarily need to know the size of the block being deallocated. It might just call some lower-level function that doesn't provide that information. Or, for example, allocated blocks might b organized into linked lists, one list for each allocated size; free() might simply release a block from that list without having to know the size.

Finally, C programmers have gotten along without such a function for decades. Adding a requirement to provide it would impose some (probably fairly small) overhead on all implementations. I think the attitude is that you can simply remember how much memory you asked for, and use that information as needed.

If you allocate a single object:

some_type *ptr = malloc(sizeof *ptr);

then sizeof *ptr gives you the size of the object. If you allocate an array:

some_type *ptr = malloc(count * sizeof *ptr);

then sizeof *ptr only gives you the size of a single element of the allocated array -- but if you remember the value of count you can compute the total requested size easily enough.

Bottom line: The C standard could have required such a function, but it's not really necessary.

UPDATE: Kerrek SB makes an excellent point in a comment, one that I hadn't thought of. I'll take the liberty of summarizing it here.

A function that operates on an array via a pointer to its initial element (and there are a lot of such functions) shouldn't have to care how the array was allocated. The proposed size() function, like the GNU-specific malloc_usable_size(), works only when the argument points to a heap-allocated array. This means that the function either has to assume that the array is heap-allocated (and be right about that assumption!) or be given extra information. In the latter case, it might as well be given the size of the array, making size() superfluous.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 1
    Think a bit further how you would use this information: Suppose you're acting on an array of `T`. If the user wants to use an automatic or static array, we need `f(T * arr, size_t len)`. If the user wants to use a malloced array, we need another `f_from_malloc(T * arr)`. But if the user only wants to act on a subarray of a given array, we need the first form again. So we will most likely want to provide the pointer+length form anyway, and at that point what do we gain from special support for malloced arrays? – Kerrek SB Jul 22 '16 at 21:25
  • @KerrekSB: An excellent point. I've appropriated it into my answer. – Keith Thompson Jul 22 '16 at 21:31
  • Allocating larger blocks than requested is a typical approach if you e.g. use a pool-based approach instead of a heap. It also does not know whether an array or a `struct` or a `union` has been allocated. Or if the allocated block is split by the application into smaller chunks (e.g. pre-allocation to get a linear address space). `free` only needs the size of the block, not the object. This would reqsult in adding the actual object size to all objects, not only dynamically allocated. -> permanent memory overhead, even for scalars. We use C beacuse we have full control over memory usage. – too honest for this site Aug 06 '16 at 14:01
2

free() may use internal data to reclaim the block of memory being released, but be aware that this data does not necessarily contain the exact size passed to malloc(), calloc(), or realloc() to allocate the block. The C Standard does not specify a function to retrieve this information.

Most malloc() implementations provide a non-standard function to retrieve the available size of the allocated block: in the Glibc, this function is size_t malloc_usable_size(void *ptr);. Other libraries may have a different function or no function at all to retrieve this information.

As for a generic solution to retrieve the size of the array to which you have a pointer, this is usually not possible. In efficient implementations, pointers do not carry size information. It is possible to implement fat pointers that would carry this information, but the whole system needs to be compiled this way. Some integrated compilers such as tcc support this approach to provide runtime pointer checking.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
chqrlie
  • 131,814
  • 10
  • 121
  • 189
0

Because basically, the address will point on a chunk of memory, which contains meta-data (such as the size of the chunk). Freeing that entry will actually mark the block available (if the pointer is valid).

If the caller access that memory location afterward, that's undefined behaviour. So even from that point of view, free will have its job done.

Aif
  • 11,015
  • 1
  • 30
  • 44
  • I don't know why folks are -1 on this. The meta data is usually just before the block that has it's address returned by malloc/calloc, but it is a trivial bug. Yes, everything not in the spec is `undefined`. In the real world, programmers should know how things work. – evaitl Jul 22 '16 at 00:12
  • 2
    I think you're arguing that the proposed `size()` function is not necessary because `free()` works without it. If that's your argument, I suggest stating it more explicitly -- but that doesn't necessarily mean a `size()` function wouldn't be useful. – Keith Thompson Jul 22 '16 at 00:12
0

free() only needs the pointer value,because you can only pass the pointer that malloc() return.The malloc() will write the size of this assign in the front address of return pointer.When you pass the pointer to free(),free() will read the size,so free() knows how many space to release.Therefor,there not used any function to find the size of a pointer array.

BobWanghz
  • 58
  • 3