1

I have a macro for calculating array sizes in my C code:

#define sizearray(a)  (sizeof(a) / sizeof((a)[0]))

When I test it, it works fine for statically defined arrays, but not so for dynamically defined arrays (see below). Not sure I understand why this is the case. Is there any way of calculating the size of an array allocated on the heap?

/* test sizearray macro */
void testSIZEARRAY(void)
{
    /* test case for statically defined array */
    int a[5] = {0,0,0,0,0};

    assert(sizearray(a) == 5);

    /* test case for dynamically defined array */
    int *b;

    b = calloc(5, sizeof(int));

    assert(sizearray(b) == 5);

    free(b);
}
bph
  • 10,728
  • 15
  • 60
  • 135
  • 2
    sizeof is evaluated at compile-time. So, no, thats not possible. – ordag Jan 05 '12 at 22:26
  • 1
    possible duplicate of [How to get the length of a dynamically created array of structs in C?](http://stackoverflow.com/questions/8717267/how-to-get-the-length-of-a-dynamically-created-array-of-structs-in-c) – Sergey Kalinichenko Jan 05 '12 at 22:27
  • possible duplicate of [Calculating size of an array](http://stackoverflow.com/questions/720077/calculating-size-of-an-array) – John Bode Jan 05 '12 at 22:49
  • @ordag `sizeof` is evaluated at compile-time if it can be. It is evaluated at runtime for VLAs. – David Heffernan Jan 05 '12 at 22:57

4 Answers4

5

The answer is no, there is no standard way to get the size of a dynamically allocated array.
For all practical purposes, you have to keep track it yourself.

However, there are some compiler-specific methods that do that:

Windows (Visual Studio): _msize()

GCC: msize() Can't find it in the GCC docs...

Mysticial
  • 464,885
  • 45
  • 335
  • 332
  • 1
    You might say that generally speaking there's no way to calculate the size of a dynamically allocated array, you just have to keep track of it. – dbeer Jan 05 '12 at 22:36
  • Does it returns the allocated size or the size which was asked? – AProgrammer Jan 06 '12 at 16:01
  • @AProgrammer Good question. I'm not sure on that and the docs aren't clear on it. – Mysticial Jan 06 '12 at 16:08
  • @AProgrammer It looks like it does return the size that was asked. I just tested it with `1` and `63`, sizes that would most certainly have been padded up - and it does return `1` and `63`. – Mysticial Jan 06 '12 at 17:37
4
int *b;
...
assert(sizearray(b) == 5);

A pointer is not an array. b is declared as pointer to int

Here

sizeof b == sizeof (int *)

The sizeof operator applied to an object of a pointer type is the same as the size of the pointer type and is not equivalent to the size of the allocated array.

To know the size of your allocated array object you have to inspect what was allocated. In your example you allocate an object of 5 int, so the size of your array is:

 5 * sizeof (int)

(or equivalent, 5 * sizeof *b)

ouah
  • 142,963
  • 15
  • 272
  • 331
3

There is no way to calculate the size of an array if you only have a pointer to its first element (as you do in the above case with int *b). You need to either store the array size separately and use it together with your pointer, or somehow mark the end of the array. The latter solution is used in character arrays, which are usually null-terminated (have \0 as their last character). In this case, you can calculate the size by looping till you encounter such a termination character.

Seramme
  • 1,340
  • 7
  • 9
1

The followng is bad advice, do not do that.

To get the memory allocated by the current glibc's malloc() (et al) you could try the following:

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

#define GLIB_MSIZE_T size_t /* We need to have a four byte unsigned integer type 
                               here. */

#define GLIB_MSIZE(p) \
        *((GLIB_MSIZE_T*) (((char*) p) - sizeof(GLIB_MSIZE_T)))

int main(int iArgC, char ** ppszArgV)
{
        if (1 >= iArgC)
        {
                fprintf(stderr, "usage: %s <bytes to allocate>\n", ppszArgV[0]);
                return EXIT_FAILURE;
        }

        {
                /* This conversion uing 'atol()' only works up until to a certain size
                   of the integer represented by 'ppszArgV[1]'. */
                size_t size = atol(ppszArgV[1]);

                void * pv = malloc(size);
                if (!pv)
                {
                        fprintf(stderr, "Allocation of %u bytes failed.\n", size);
                        return EXIT_FAILURE;
                }

                printf("Asked for %u bytes, got %u bytes.\n", size, GLIB_MSIZE(pv));
        }

        return EXIT_SUCCESS;
}

Besides the fact one indeed could get the amount of memory allocated, the interesting thing to see when paying with this code is, that in most of the cases more then the size of memory requested is assigned.

Anyhow, the latter makes it unsafe trying to pull information from this on the exact size originally requested.

alk
  • 69,737
  • 10
  • 105
  • 255