2

I am curious why I am getting the following behaviour in my code.

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


int main(int argc, char *argv[])
{
    int M=24;
    int arr[M];
    int N=24;
    int* ptr=(int*) malloc(sizeof(int)*N); /*Allocate memory of size N  */

    printf("Size of your malloced array is %lu\n",sizeof(ptr)/sizeof(ptr[0])); /* Get the size of memory alloctaed. Should be the same as N?*/

    printf ("Size of your normal arrays is %lu\n",sizeof(arr)/sizeof(arr[0])); /* Ditto  */

    free(ptr);

    return 0;
}

The output is

Size of your malloced array is 2
Size of your normal arrays is 24

I would have thought the output would be 24 in both places. How then does one get the size of the malloced array If somehow I have "forgotten" it?

Surely the pointer ptr will contain some information about the size of the malloced array since when we call free(ptr) it will release the array just malloced

In silico
  • 51,091
  • 10
  • 150
  • 143
smilingbuddha
  • 14,334
  • 33
  • 112
  • 189
  • Why are you using `malloc` in C++ code? – John Dibling Dec 13 '11 at 19:47
  • Your tags are a little ambiguous. Anyway, if this is C, you have to keep track of the size yourself, like @Mysticial said. If this is C++, however, generally you will use a `std::vector` or similar structure and won't bother as it will do it for you. – netcoder Dec 13 '11 at 19:51
  • Yes thanks for pointing that out. I meant this to be a C question. Tagged it as C++ by mistake. – smilingbuddha Dec 13 '11 at 19:53
  • possible duplicate of [newbie questions about malloc and sizeof](http://stackoverflow.com/questions/1533519/newbie-questions-about-malloc-and-sizeof). see also http://c-faq.com/malloc/sizeof.html – Jens Gustedt Dec 13 '11 at 19:53
  • To repeat what others have said: you are wrong if you think that "Surely the pointer ptr will contain some information about the size of the malloced." The fact is that the pointer contains ***NO*** information about the size of the malloced array. It contains information about the start of the malloced array and nothing else. You have to maintain (ie., remember) the size of the array. – Pete Wilson Dec 13 '11 at 19:59

6 Answers6

7

When you use sizeof() on a pointer, you get the size of the pointer. Not the size of the allocated array. In your case, a pointer is probably 8 bytes and an int is 4 bytes, hence why you get 2.

In short, you can't get the size of an allocated array. You need to keep track of it yourself.


EDIT : Note that some compilers do actually support this functionality as an extension:

For example, MSVC supports _msize(): http://msdn.microsoft.com/en-us/library/z2s077bc.aspx

Mysticial
  • 464,885
  • 45
  • 335
  • 332
  • Thank you for this information. But then when free function is called we only specify the pointer `ptr`. How then does the computer know to clean up the 'N' succcessive memory locations from that address? – smilingbuddha Dec 13 '11 at 19:59
  • That's an implementation detail, and is not specified by the standard. In many cases, the size information is actually *known* internally, but there's no standard C method to get that information as the user. – Mysticial Dec 13 '11 at 20:04
  • Does `_msize()` give you the size that was requested in the `malloc()` call, or the size actually allocated? It's not clear from the `_msize()` description, but the [`malloc()`](http://msdn.microsoft.com/en-us/library/6ewkz86d.aspx) description does say that it may allocate a larger block than requested. – Keith Thompson Dec 13 '11 at 20:35
  • @KeithThompson That's a good question, and I don't know - since I've never used it before. – Mysticial Dec 13 '11 at 20:36
3

While sizeof() works as you'd expect with fixed-length and variable-length arrays, it doesn't know anything about the sizes of malloc()'ed arrays.

When applied to a pointer, sizeof() simply returns the size of the pointer.

More generally, given a pointer to a malloc()'ed block, there's no standard way to discover the size of that block.

See C FAQ questions 7.27 and 7.28.

In summary, if you need to know the size of a heap-allocated array in a portable manner, you have to keep track of that size yourself.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Well, mostly. In the sample code in the question, `arr` is actually a variable-length array (VLA), since `M` is not a constant expression. VLAs were added to the language in C99. – Keith Thompson Dec 13 '11 at 19:55
  • @KeithThompson: Good point, thanks. I've reworded the answer to address this. – NPE Dec 13 '11 at 19:58
1

You cannot obtain, at runtime, the size of an array if you only have a pointer to (the first element of) the array. There are no constructs at all in C that allow you to do this. You have to keep track of the length yourself.

If you happen to have an array rather than a pointer then you can find its length, but not for a pointer to an element of the array.

In your code, ptr is a pointer and so you cannot find out the length of the array to which it points. On the other hand, arr is an array and so you can find out its length with sizeof(arr)/sizeof(arr[0]).

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
0

The size of a pointer is 4 bytes on 32-bit machines and 8 bytes on 64-bit machines. I guess you work on a 64-bit machine since the size of an int is 4, and you got that sizeof(ptr)/sizeof(ptr[0]) is 2.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
kol
  • 27,881
  • 12
  • 83
  • 120
0

As this other question points out, there is no portable way getting the size of a dynamic array, since malloc may allocate more memory than requested. Furthermore managing malloc requests is up to the operating system. For instance *nix would calls sbrkand store the requests somewhere. So, when you call sizeof(ptr) it returns the size of the pointer and not the size of the array. On the other hand, if your array is fixed, the size of it is determined at compile time, so the compiler is able to replace sizeof(arr) with the size of the fixed array, thus providing you the "correct" size.

Community
  • 1
  • 1
Sebastian
  • 8,046
  • 2
  • 34
  • 58
0

The thing to remember about sizeof is that it is a compile-time operator1; it returns the number of bytes based on the type of the operand.

The type of arr is int [24], so sizeof arr will evaluate to the number of bytes required to store 24 int values. The type of ptr is int *, so sizeof ptr will evaluate to the number of bytes required to store a single int * value. Since this happens at compile time, there's no way for sizeof to know what block of memory ptr is pointing to or how large it is.

In general, you cannot determine how large a chunk of memory a pointer points to based on the pointer value itself; that information must be tracked separately.

Stylistic nit: a preferred way to write the malloc call is

int *ptr = malloc(sizeof *ptr * N);

In C, you do not need to cast the result of malloc to the target pointer type2, and doing so can potentially mask a useful diagnostic if you forget to include stdlib.h or otherwise don't have a prototype for malloc in scope.

Secondly, notice that I pass the expression *ptr as the operand to sizeof rather than (int). This minimizes bugs in the event you change the type of ptr but forget to change the type in the corresponding malloc call. This works because sizeof doesn't attempt to evaluate the operand (meaning it doesn't attempt to dereference ptr); it only computes its type.


1 The exception to this rule occurs when sizeof is applied to a variable-length array; since the size of the array isn't determined until runtime, a sizeof operator applied to a VLA will be evaluated at runtime.

2 Note that this is not the case in C++; a cast is required, but if you're writing C++ you should be using new and delete instead of malloc and free anyway. Also, this is only true since C89; older versions of C had malloc return char * instead of void *, so for those versions the cast was required. Unless you are working on a very old implementation (such as an old VAX mini running an ancient version of VMS), this shouldn't be an issue.
John Bode
  • 119,563
  • 19
  • 122
  • 198