By jkidv


2009-01-29 16:33:34 8 Comments

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)?

13 comments

@Tᴏᴍᴇʀ Wᴏʟʙᴇʀɢ 2018-06-22 11:42:34

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;

@baz 2017-03-11 11:56:01

hi in strings there is a '\0' character at the end so one can get the size of 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

/* http://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array */
#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 );
}
/* край */

@Fabio Turati 2017-03-11 12:16:38

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!

@Peter Cordes 2018-06-19 03:03:09

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.

@DigitalRoss 2016-07-25 20:50:19

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.

@Shivangi Chaurasia 2016-07-10 10:32:16

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.

@Amitābha 2016-12-27 04:33:11

sizeof(ptr) is the size of pointer and sizeof(*ptr) is the size of pointer to which

@SKD 2016-03-15 11:22:40

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.

@user4713908 2015-10-05 14:45:29

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]);
    }
    else
        printf("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.

@user3065147 2014-03-11 08:27:39

 #define array_size 10

 struct {
     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 30

struct {
    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;
    }
}

@Ryan 2009-01-29 17:12:46

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]))
#endif

int 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.

@Sanjaya R 2009-01-29 17:19:28

ARRAY_SIZE is a common paradigm used by practical programmers everywhere.

@Ryan 2009-01-29 17:27:51

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.

@Paul Tomblin 2009-01-29 17:40:44

Yes, good point, but the question being asked was about the pointer one, not the static array one.

@newacct 2013-02-28 18:52:43

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.

@Natalie Adams 2013-04-23 02:24:50

There is a template function floating around that does the same thing but will prevent the use of pointers.

@Ryan 2013-04-24 14:55:31

@newacct I think you are getting caught up in semantics. My point was simply that macros do not have type checking. If you pass a pointer to the macro, you will not get the intended result. If you can use the C++ template equivalent, it is safer -- but the OP asked about C.

@Fehmi Noyan ISI 2018-05-16 21:05:41

The ARRAY_SIZE macro, with a different name, is used in K&R C 2nd edition. Not a good practice nowadays, but the language itself does not offer a solution.

@jxh 2013-04-09 17:21:56

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 10

void 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.

@Max 2013-08-17 01:12:10

+1 for "You cannot get this information from the decayed pointer value of the array alone" and providing a workaround.

@Paul Tomblin 2009-01-29 16:39:57

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.

@viki.omega9 2013-03-03 19:19:55

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?

@Paul Tomblin 2013-03-03 20:48:57

@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).

@viki.omega9 2013-03-03 22:52:44

Quick follow up, why isn't there a function that can return the size the way free does?

@Paul Tomblin 2013-03-03 23:11:31

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.

@RouteMapper 2013-11-15 18:10:32

Isn't this a problem if the pointer isn't inside any allocated memory at all? We would never be able to find the out-of-band value nor would we be able to find the stashed size of the array. Am I off here?

@Paul Tomblin 2013-11-15 18:31:35

@RouteMapper, there are lots of problems with the "tricks". That's why I called them tricks. The language doesn't provide robust support for finding out the side of an allocated array, and it's going to be up to you to find the solution that works for your use-case.

@RouteMapper 2013-11-15 18:40:09

@PaulTomblin, do you think there's a better way to do it in an intermediate language? Say, LLVM IR?

@Zan Lynx 2014-07-20 03:48:32

@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.

@Dhruv Mullick 2015-02-01 14:11:04

@PaulTomblin: Can you explain what the difference between days and ptr is? Both of them are integer pointers which contain the address to the first element of the array.

@Lightness Races in Orbit 2015-03-14 15:21:03

Have a badge.​​

@Jon Wheelock 2015-10-14 08:08:14

Is it possible if we pass the pointer to entire array like char (*ptr)[size] ? In this case ptr is defined as char (*ptr)[size] = &days;. But I am not sure how we get the size inside the function.

@Paul Tomblin 2015-10-14 12:30:31

@JonWheelock no, that won't help. The pointer does not retain the size information.

@skurton 2012-04-19 11:53:43

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;
}

Output:

3
5

@WorldSEnder 2014-06-04 09:43:44

I have never seen the notation T (&)[SIZE]. Can you explain what this means? Also you could mention constexpr in this context.

@Oguk 2014-10-12 07:02:09

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.

@user2796283 2016-08-28 10:43:57

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?

@Peter Cordes 2018-06-19 02:53:14

@WorldSEnder: That's C++ syntax for a reference of array type (with no variable name, just a size and element-type).

@Peter Cordes 2018-06-19 02:55:04

@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.)

@zett42 2018-10-31 14:05:07

As of C++17, we have std::size(), which is similar to your getSize() function and in addition has an overload for containers, that provide a size() member function.

@Zan Lynx 2009-01-29 16:42:28

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.

@dsm 2009-01-29 16:44:30

Thats how pascal strings are implemented

@Adam Naylor 2010-07-14 19:48:42

and apparently pascal strings are why excel runs so fast!

@Zan Lynx 2010-07-14 19:52:28

@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.

@David 2011-04-13 21:04:15

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 5
typedef 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;
} 

Output:

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

Related Questions

Sponsored Content

76 Answered Questions

[SOLVED] How do I remove a particular element from an array in JavaScript?

  • 2011-04-23 22:17:18
  • Walker
  • 5490233 View
  • 6813 Score
  • 76 Answer
  • Tags:   javascript arrays

34 Answered Questions

33 Answered Questions

[SOLVED] Create ArrayList from array

44 Answered Questions

31 Answered Questions

[SOLVED] For-each over an array in JavaScript?

30 Answered Questions

[SOLVED] How to append something to an array?

10 Answered Questions

17 Answered Questions

[SOLVED] With arrays, why is it the case that a[5] == 5[a]?

9 Answered Questions

[SOLVED] Improve INSERT-per-second performance of SQLite?

18 Answered Questions

[SOLVED] How do I empty an array in JavaScript?

  • 2009-08-05 09:08:39
  • amir
  • 2108088 View
  • 2199 Score
  • 18 Answer
  • Tags:   javascript arrays

Sponsored Content