12

I have a buffer and want to do a test to see if the buffer has sufficient capacity I.e. find number of elements I can add to the buffer.

char *buffer = (char *)malloc(sizeof(char) * 10);

Doing a

int numElements = sizeof(buffer); 

does not return 10, any ideas on how I can accomplish this?

Jens
  • 69,818
  • 15
  • 125
  • 179
godzilla
  • 3,005
  • 7
  • 44
  • 60
  • 2
    Possible duplicate of [How can I get the size of a memory block allocated using malloc()?](https://stackoverflow.com/q/1208644/608639), [How can I get the size of an array from a pointer in C?](https://stackoverflow.com/q/232691/608639) And related is [Determine the size of a C++ array programmatically?](https://stackoverflow.com/q/197839/608639) – jww Mar 03 '19 at 20:20

5 Answers5

27

For GNU glibc:

SYNOPSIS

#include <malloc.h>
size_t malloc_usable_size (void *ptr);

DESCRIPTION

The malloc_usable_size() function returns the number of usable bytes in the block pointed to by ptr, a pointer to a block of memory allocated by malloc(3) or a related function.

Wasi Ahmad
  • 35,739
  • 32
  • 114
  • 161
Vitaly
  • 279
  • 3
  • 2
  • 1
    Note: That can lead to serious overhead because it's depend of malloc implementation. And it returns bytes allocated. To get the number of elements available you need an additional division. The man clearly says "The value returned by malloc_usable_size() may be greater than the requested size of the allocation because of alignment and minimum size constraints. Although the excess bytes can be overwritten by the application without ill effects, **this is not good programming practice**: the number of excess bytes in an allocation depends on the underlying implementation." – Stargateur Dec 29 '16 at 05:37
18

You cannot make such a test. It is your own responsibility to remember how much memory you allocated. If the buffer is given to you by someone else, demand that they pass the size information as well, and make it their responsibility to pass the correct value or have the program die.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 2
    How can you determine if they passed the correct value? – user124384 Feb 08 '19 at 20:29
  • 2
    @user124384: You cannot. Instead, you document the requirements of your library, and it is your user's responsibility to read, understand and abide by the contract. You're not responsible for that. Dynamic memory debuggers (like Valgrind or ASAN) can help verify individual programs, but nothing C can. You can also hide your library behind some opaque abstraction boundary and do all the allocation and deallocation behind the scenes, so users only get to pass opaque handles around. (But that would be the answer to a different question!) – Kerrek SB Feb 08 '19 at 21:41
8

buffer is just a pointer without size information. However the malloc() routine will hold the size of the allocation you made so when you free() it, it frees the right amount of space. So unless you want to dive in the malloc() functionality, I recommend you just save the size of the allocation yourself. (for a possible implementation, see the example in the other API answer).

Evert
  • 563
  • 1
  • 5
  • 13
5

Since buffer is a pointer (not an array), the sizeof operator returns the size of a pointer, not the size of the buffer it points to. There is no standard way to determine this size, so you have to do the bookkeeping yourself (i.e. remember how much you allocated.)

BTW, it's the same for

 char *p = "hello, world\n"; /* sizeof p is not 13. */

Interestingly,

 sizeof "hello, world\n"

is 14. Can you guess why?

Jens
  • 69,818
  • 15
  • 125
  • 179
  • 34
    Are you really passing a question back at the questioner? That's not really why we're here... – Evert May 17 '12 at 16:38
  • @Jens Well I know that sizeof() returns the correct size for string literals and arrays, but why? Where's the size information stored? For example char*p = "hello" gives size of pointer, char p[10] gives size of ten. – Zebrafish May 27 '16 at 15:54
  • 6
    @Evert We are here to get answers, and he gave an answer. Posing followup questions is a legitimate education device. Further I don't think his question warrants criticism because the answer to his question is the answer he just gave, so he is not really hiding information. I suppose one could debate the efficacy or value leaving "an excercise for the reader", etc, but in this case it is quite concise and relevant. – Wilbur Whateley Dec 22 '16 at 22:58
  • 3
    @WilburWhateley No good deed goes unpunished. My answer even got downvoted. Anyone thinking about the follow-up question, which was posed in the time-tested educational style of guiding a learner to a self-made discovery, might gain an insight about string literals and strings. – Jens Dec 23 '16 at 08:33
  • 1
    I actually took an important lesson here - that C string constants are char arrays - not pointers to arbitrary sized buffers. That's a good and important point. – Motti Shneor Mar 17 '19 at 07:24
3
struct buffer
{
  void
    *memory

  size_t
    length;
};

void *buffer_allocate( struct buffer *b, size_t length )
{
  assert( b != NULL );

  b->memory = malloc( length )
  b->length = length;

      // TRD : NULL on malloc() fail
      return( b->memory );
}

int buffer_valid( struct buffer *b, size_t length )
{
  assert( b != NULL );

  if( b->memory == NULL or length > b->length )
    return( 0 );

  return( 1 );
}

void *buffer_get( struct buffer *b )
{
  assert( b != NULL );

  return( b->memory );
}

Use the API and not malloc/free and you can't go wrong.

  • If you really wanted to be clever, you could write your own `malloc` that used the system `malloc` to allocate four extra bytes, store the length allocated there and returned a pointer after this length. Then you could have a `getSize` method that used pointer arithmetic to grab this out again. It lets you use calls that look like `malloc` and `free`. – Gort the Robot May 17 '12 at 16:49
  • I'm not sure that's clever - it means your personal malloc now differs in its behaviour to everyone elses. I've come to the view adjusting core function behaviour is risky. It underpins everything else. –  May 17 '12 at 17:00
  • 1
    I knew one company, over-rode malloc so that everything it allocated went onto freelists, and free just returned the element to the freelist. Appalling, both in what it does and actually also in how it was implemented (not surprising, given how bad the idea is) and so deeply embedded in the code it could never be removed. –  May 17 '12 at 17:01
  • I like this, because it un-hides the fact that malloc/calloc don't really make any record of what you asked them to allocate. These methods will allocate enough for you - sometimes a little more, and differently aligned than what you ask for, but will not remember the original num of elements you asked for. It's better to have our OWN definition of a buffer, which includes both its start-pointer and its length (in elements) – Motti Shneor Mar 17 '19 at 07:22