First off, here is some code:

int main() {int days[]={1,2,3,4,5};int *ptr=days;printf("%u\n", sizeof(days));printf("%u\n", sizeof(ptr));return 0;}

Is there a way to find out the size of the array that ptr is pointing to (instead of just giving its size, which is four bytes on a 32-bit system)?

  • 79
    I've always used parens with sizeof - sure it makes it look like a function call, but I think it's clearer.– Paul TomblinJan 29 '09 at 16:44
  • 17
    Why not? Do you have something against superfluous parentheses? I think it reads a little more easily with them, myself.– David ThornleyJan 29 '09 at 16:44
  • 5
    @Paul: well .. assuming the left hand side of that call is a pointer to int, I'd write it as int *ptr=malloc(4 * sizeof *ptr); which to me is far clearer. Less parens to read, and bringing the literal constsant to the front, like in maths.– unwindJan 29 '09 at 17:32
  • 3
    @unwind - don't allocate an array of pointers when you meant an array of ints!– Paul TomblinJan 29 '09 at 17:47
  • 5
    There is no "pointer pointing to an array" here. Just a pointer pointing to an int.– newacctFeb 28 '13 at 19:01

13 Answers13

up vote226down voteaccepted

No, you can't. The compiler doesn't know what the pointer is pointing to. There are tricks, like ending the array with a known out-of-band value and then counting the size up until that value, but that's not using sizeof.

Another trick is the one mentioned by Zan, which is to stash the size somewhere. For example, if you're dynamically allocating the array, allocate a block one int bigger than the one you need, stash the size in the first int, and return ptr+1 as the pointer to the array. When you need the size, decrement the pointer and peek at the stashed value. Just remember to free the whole block starting from the beginning, and not just the array.

  • 8
    I'm sorry for this posting a comment so late but if the compiler does not know what the pointer is pointing to how does free know how much memory to clear? I do know that this information is stored internally for functions like free to use. So my question is why can' the compiler do so too?– viki.omega9Mar 3 '13 at 19:19
  • 9
    @viki.omega9, because free discovers the size at runtime. The compiler can't know the size because you could make the array a different size depending on runtime factors (command line arguments, contents of a file, phase of moon,etc).– Paul TomblinMar 3 '13 at 20:48
  • 8
    Quick follow up, why isn't there a function that can return the size the way free does?– viki.omega9Mar 3 '13 at 22:52
  • 4
    Well, if you could guarantee that the function was only called with malloced memory and the library tracks the malloced memory the way most I've seen do (by using an int before the returned pointer) then you could write one. But if the pointer is to a static array or the like, it would fail. Similarly, there is no guarantee that the size of malloced memory is accessible to your program.– Paul TomblinMar 3 '13 at 23:11
  • 7
    @viki.omega9: Another thing to keep in mind is that the size recorded by the malloc/free system may not be the size you asked for. You malloc 9 bytes and get 16. Malloc 3K bytes and get 4K. Or similar situations.– Zan LynxJul 20 '14 at 3:48

The answer is, "No."

What C programmers do is store the size of the array somewhere. It can be part of a structure, or the programmer can cheat a bit and malloc() more memory than requested in order to store a length value before the start of the array.

  • 3
    Thats how pascal strings are implemented– dsmJan 29 '09 at 16:44
  • 5
    and apparently pascal strings are why excel runs so fast!– Adam NaylorJul 14 '10 at 19:48
  • 6
    @Adam: It is fast. I use it in a list of strings implementation of mine. It is super-fast to linear search because it is: load size, prefetch pos+size, compare size to search size, if equal strncmp, move to next string, repeat. It's faster than binary search up to about 500 strings.– Zan LynxJul 14 '10 at 19:52

For dynamic arrays (malloc or C++ new) you need to store the size of the array as mentioned by others or perhaps build an array manager structure which handles add, remove, count, etc. Unfortunately C doesn't do this nearly as well as C++ since you basically have to build it for each different array type you are storing which is cumbersome if you have multiple types of arrays that you need to manage.

For static arrays, such as the one in your example, there is a common macro used to get the size, but it is not recommended as it does not check if the parameter is really a static array. The macro is used in real code though, e.g. in the Linux kernel headers although it may be slightly different than the one below:

#if !defined(ARRAY_SIZE)#define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))#endifint main(){int days[]={1,2,3,4,5};int *ptr=days;printf("%u\n", ARRAY_SIZE(days));printf("%u\n", sizeof(ptr));return 0;}

You can google for reasons to be wary of macros like this. Be careful.

If possible, the C++ stdlib such as vector which is much safer and easier to use.

  • 10
    ARRAY_SIZE is a common paradigm used by practical programmers everywhere.– Sanjaya RJan 29 '09 at 17:19
  • 4
    Yes it is a common paradigm. You still need to use it cautiously though as it is easy to forget and use it on a dynamic array.– RyanJan 29 '09 at 17:27
  • 2
    Yes, good point, but the question being asked was about the pointer one, not the static array one.– Paul TomblinJan 29 '09 at 17:40
  • 2
    That ARRAY_SIZE macro always works if its argument is an array (i.e. expression of array type). For your so-called "dynamic array", you never get an actual "array" (expression of array type). (Of course, you can't, since array types include their size at compile-time.) You just get a pointer to the first element. Your objection "does not check if the parameter is really a static array" is not really valid, since they are different as one is an array and the other isn't.– newacctFeb 28 '13 at 18:52
  • 2
    There is a template function floating around that does the same thing but will prevent the use of pointers.– Nathan AdamsApr 23 '13 at 2:24

There is a clean solution with C++ templates, without using sizeof(). The following getSize() function returns the size of any static array:

#include <cstddef>template<typename T, size_t SIZE>size_t getSize(T (&)[SIZE]) {return SIZE;}

Here is an example with a foo_t structure:

#include <cstddef>template<typename T, size_t SIZE>size_t getSize(T (&)[SIZE]) {return SIZE;}struct foo_t {int ball;};int main(){foo_t foos3[]={{1},{2},{3}};foo_t foos5[]={{1},{2},{3},{4},{5}};printf("%u\n", getSize(foos3));printf("%u\n", getSize(foos5));return 0;}


  • I have never seen the notation T (&)[SIZE]. Can you explain what this means? Also you could mention constexpr in this context.– WorldSEnderJun 4 '14 at 9:43
  • 1
    That's nice if you use c++ and you actually have a variable of an array type. Neither of them is the case in the question: Language is C, and the thing the OP wants to get the array size from is a simple pointer.– OgukOct 12 '14 at 7:02
  • would this code lead to code bloat by recreating the same code for every different size/type combination or is that magically optimised out of existence by the compiler?– user2796283Aug 28 '16 at 10:43
  • @WorldSEnder: That's C++ syntax for a reference of array type (with no variable name, just a size and element-type).– Peter CordesJun 19 at 2:53
  • @user2796283: This function is optimized away entirely at compile time; no magic is needed; it's not combining anything to a single definition, it's simply inlining it away to a compile-time constant. (But in a debug build, yes, you'd have a bunch of separate functions that return different constants. Linker magic might merge ones that use the same constant. The caller doesn't pass SIZE as an arg, it's a template param that has to already be known by the function definition.)– Peter CordesJun 19 at 2:55

For this specific example, yes, there is, IF you use typedefs (see below). Of course, if you do it this way, you're just as well off to use SIZEOF_DAYS, since you know what the pointer is pointing to.

If you have a (void *) pointer, as is returned by malloc() or the like, then, no, there is no way to determine what data structure the pointer is pointing to and thus, no way to determine its size.

#include <stdio.h>#define NUM_DAYS 5typedef int days_t[ NUM_DAYS ];#define SIZEOF_DAYS ( sizeof( days_t ) )int main() {days_t days;days_t *ptr=&days; printf( "SIZEOF_DAYS: %u\n", SIZEOF_DAYS );printf( "sizeof(days): %u\n", sizeof(days) );printf( "sizeof(*ptr): %u\n", sizeof(*ptr) );printf( "sizeof(ptr): %u\n", sizeof(ptr) );return 0;} 


SIZEOF_DAYS: 20sizeof(days): 20sizeof(*ptr): 20sizeof(ptr): 4

    There is no magic solution. C is not a reflective language. Objects don't automatically know what they are.

    But you have many choices:

    1. Obviously, add a parameter
    2. Wrap the call in a macro and automatically add a parameter
    3. Use a more complex object. Define a structure which contains the dynamic array and also the size of the array. Then, pass the address of the structure.

      As all the correct answers have stated, you cannot get this information from the decayed pointer value of the array alone. If the decayed pointer is the argument received by the function, then the size of the originating array has to be provided in some other way for the function to come to know that size.

      Here's a suggestion different from what has been provided thus far,that will work: Pass a pointer to the array instead. This suggestion is similar to the C++ style suggestions, except that C does not support templates or references:

      #define ARRAY_SZ 10void foo (int (*arr)[ARRAY_SZ]) {printf("%u\n", (unsigned)sizeof(*arr)/sizeof(**arr));}

      But, this suggestion is kind of silly for your problem, since the function is defined to know exactly the size of the array that is passed in (hence, there is little need to use sizeof at all on the array). What it does do, though, is offer some type safety. It will prohibit you from passing in an array of an unwanted size.

      int x[20];int y[10];foo(&x); /* error */foo(&y); /* ok */

      If the function is supposed to be able to operate on any size of array, then you will have to provide the size to the function as additional information.

      • +1 for "You cannot get this information from the decayed pointer value of the array alone" and providing a workaround.– MaxAug 17 '13 at 1:12

      My solution to this problem is to save the length of the array into a struct Array as a meta-information about the array.

      #include <stdio.h>#include <stdlib.h>struct Array{int length;double *array;};typedef struct Array Array;Array* NewArray(int length){/* Allocate the memory for the struct Array */Array *newArray=(Array*) malloc(sizeof(Array));/* Insert only non-negative length's*/newArray->length=(length > 0) ? length : 0;newArray->array=(double*) malloc(length*sizeof(double));return newArray;}void SetArray(Array *structure,int length,double* array){structure->length=length;structure->array=array;}void PrintArray(Array *structure){ if(structure->length > 0){int i;printf("length: %d\n", structure->length);for (i=0; i < structure->length; i++)printf("%g\n", structure->array[i]);}elseprintf("Empty Array. Length 0\n");}int main(){int i;Array *negativeTest, *days=NewArray(5);double moreDays[]={1,2,3,4,5,6,7,8,9,10};for (i=0; i < days->length; i++)days->array[i]=i+1;PrintArray(days);SetArray(days,10,moreDays);PrintArray(days);negativeTest=NewArray(-5);PrintArray(negativeTest);return 0;}

      But you have to care about set the right length of the array you want to store, because the is no way to check this length, like our friends massively explained.

        int main() {int days[]={1,2,3,4,5};int *ptr=days;printf("%u\n", sizeof(days));printf("%u\n", sizeof(ptr));return 0;}

        Size of days[] is 20 which is no of elements * size of it's data type.While the size of pointer is 4 no matter what it is pointing to.Because a pointer points to other element by storing it's address.

        • 1
          sizeof(ptr) is the size of pointer and sizeof(*ptr) is the size of pointer to which– AmitābhaDec 27 '16 at 4:33

        No, you can't use sizeof(ptr) to find the size of array ptr is pointing to.

        Though allocating extra memory(more than the size of array) will be helpful if you want to store the length in extra space.

          You can do something like this:

          int days[]={ /*length:*/5, /*values:*/ 1,2,3,4,5 };int *ptr=days + 1;printf("array length: %u\n", ptr[-1]);return 0;
             #define array_size 10struct {int16 size;int16 array[array_size];int16 property1[(array_size/16)+1]int16 property2[(array_size/16)+1]} array1={array_size, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};#undef array_size

            array_size is passing to the size variable:

            #define array_size 30struct {int16 size;int16 array[array_size];int16 property1[(array_size/16)+1]int16 property2[(array_size/16)+1]} array2={array_size};#undef array_size

            Usage is:

            void main() {int16 size=array1.size;for (int i=0; i!=size; i++) {array1.array[i] *=2;}}

              hi in strings there is a '\0' character at the end so one can get the sizeof a string with functions like strlen the problem with an integer array for example is that u can't use any value as an end value so one possible solution is to address the array and use as an end value the NULL pointer

              /* */#include <stdio.h>/* the following function will produce the warning:* ‘sizeof’ on array function parameter ‘a’ will* return size of ‘int *’ [-Wsizeof-array-argument]*/void foo( int a[] ){printf( "%lu\n", sizeof a );}/* so we have to implement something else one possible* idea is to use the NULL pointer as a control value* the same way '\0' is used in strings but this way* the pointer passed to a function should address pointers* so the actual implementation of an array type will* be a pointer to pointer*/typedef char * type_t; /* line 18 */typedef type_t ** array_t;/** -- --* -**-**-* -$$$$$-* -999-* -^-* -*/int main( void ){array_t initialize( int, ... );/* initialize an array with four values "foo", "bar", "baz", "foobar"* if one wants to use integers rather than strings than in the typedef* declaration at line 18 the char * type should be changed with int* and in the format used for printing the array values * at line 45 and 51 "%s" should be changed with "%i"*/array_t array=initialize( 4, "foo", "bar", "baz", "foobar" );int size( array_t );/* print array size */printf( "size %i:\n", size( array ));void aprint( char *, array_t );/* print array values */aprint( "%s\n", array ); /* line 45 */type_t getval( array_t, int );/* print an indexed value */int i=2;type_t val=getval( array, i );printf( "%i: %s\n", i, val ); /* line 51 */void delete( array_t );/* free some space */delete( array );return 0;}/* the output of the program should be:* size 4:* foo* bar* baz* foobar* 2: baz*/#include <stdarg.h>#include <stdlib.h>array_t initialize( int n, ... ){/* here we store the array values */type_t *v=(type_t *) malloc( sizeof( type_t ) * n );va_list ap;va_start( ap, n );int j;for ( j=0; j < n; j++ )v[j]=va_arg( ap, type_t );va_end( ap );/* the actual array will hold the addresses of those* values plus a NULL pointer*/array_t a=(array_t) malloc( sizeof( type_t *) * ( n + 1 ));a[n]=NULL;for ( j=0; j < n; j++ )a[j]=v + j;return a;}int size( array_t a ){int n=0;while ( *a++ !=NULL )n++;return n;}void aprint( char *fmt, array_t a ){while ( *a !=NULL )printf( fmt, **a++ ); }type_t getval( array_t a, int i ){return *a[i];}void delete( array_t a ){free( *a );free( a );}/* край */
              • Your code is full of comments, but I think it would make everything easier if you added some general explanation of how this works outside of code, as normal text. Can you please edit your question and do it? Thank you!– Fabio TuratiMar 11 '17 at 12:16
              • Creating an array of pointers to each element so you can linear-search it for NULL is probably the least efficient alternative imaginable to just storing a separate size directly. Especially if you actually use this extra layer of indirection all the time.– Peter CordesJun 19 at 3:03

              protected by Lundin Apr 16 '14 at 14:02

              Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

              Would you like to answer one of these unanswered questions instead?

              Not the answer you're looking for? Browse other questions tagged or ask your own question.