determine size of array if passed to function

Viewed 36490

Is it possible to determine the size of an array if it was passed to another function (size isn't passed)? The array is initialized like int array[] = { XXX } ..

I understand that it's not possible to do sizeof since it will return the size of the pointer .. Reason I ask is because I need to run a for loop inside the other function where the array is passed. I tried something like:

for( int i = 0; array[i] != NULL; i++) {
........
}

But I noticed that at the near end of the array, array[i] sometimes contain garbage values like 758433 which is not a value specified in the initialization of the array..

10 Answers

The other answers overlook one feature of c++. You can pass arrays by reference, and use templates:

template <typename T, int N>
void func(T (&a) [N]) {
    for (int i = 0; i < N; ++i) a[i] = T(); // reset all elements
}

then you can do this:

int x[10];
func(x);

but note, this only works for arrays, not pointers.

However, as other answers have noted, using std::vector is a better choice.

If it's within your control, use a STL container such as a vector or deque instead of an array.

Nope, it's not possible.

One workaround: place a special value at the last value of the array so you can recognize it.

One obvious solution is to use STL. If it's not a possibility, it's better to pass array length explicitly. I'm skeptical about use the sentinel value trick, for this particular case. It works better with arrays of pointers, because NULL is a good value for a sentinel. With array of integers, it's not that easy - you need to have a "magic" sentinel value, which is not good.

Side note: If your array is defined and initalized as

 int array[] = { X, Y, Z };

in the same scope as your loop, then

sizeof(array) will return it's real size in bytes, not the size of the pointer. You can get the array length as

sizeof(array) / sizeof(array[0])

However, in general case, if you get array as a pointer, you can't use this trick.

If you can't pass the size, you do need a distinguishable sentinel value at the end (and you need to put it there yourself -- as you've found, you can't trust C++ to do it automagically for you!). There's no way to just have the called function magically divine the size, if that's not passed in and there is no explicit, reliable sentinel in use.

Can you try appending a null character \0 to the array and then send it? That way, you can just check for \0 in the loop.

I originally had this as an answer to this other question: When a function has a specific-size array parameter, why is it replaced with a pointer?, but just moved it here instead since it more-directly answers this question.


Building off of @Richard Corden's answer and @sbi's answer, here's a larger example demonstrating the principles of:

  1. Enforcing a given function parameter input array size using a reference to an array of a given size, like this:

     void foo2(uint8_t (&array)[100]) 
     {
         printf("sizeof(array) = %lu\n", sizeof(array)); 
     }
    

    and:

  2. Allowing a function parameter input array of any size, by using a function template with a reference to an input array of a given template parameter size N, like this:

     template<size_t N>
     void foo3(uint8_t (&array)[N])
     {
         printf("sizeof(array) = %lu\n", sizeof(array)); 
     }
    

Looking at the full example below:

Notice how this function prototype doesn't know the array size at all! (the 100 here is simply a visual hint/reminder to the human user, but has no bearing or influence on the compiler whatsoever!):

void foo(uint8_t array[100]) {}

...this function prototype allows only input arrays of a fixed size of 100:

void foo2(uint8_t (&array)[100]) {}

...and this function template prototype allows arrays of ANY input size AND knows their size statically at compile-time (as that is how templates work):

template<size_t N>
void foo3(uint8_t (&array)[N]) {}

Here's the full example:

You can run it yourself here: https://onlinegdb.com/rkyL_tcBv.

#include <cstdint>
#include <cstdio>

void foo(uint8_t array[100]) 
{
    // is ALWAYS sizeof(uint8_t*), which is 8!
    printf("sizeof(array) = %lu\n", sizeof(array)); 
}

void foo2(uint8_t (&array)[100]) 
{
    printf("sizeof(array) = %lu\n", sizeof(array)); 
}

template<size_t N>
void foo3(uint8_t (&array)[N])
{
    printf("sizeof(array) = %lu\n", sizeof(array)); 
}


int main()
{
    printf("Hello World\n");
    printf("\n");
    
    uint8_t a1[10];
    uint8_t a2[11];
    uint8_t a3[12];
    
    // Is `sizeof(array) = 8` for all of these!
    foo(a1);
    foo(a2);
    foo(a3);
    printf("\n");
    
    // Fails to compile for these 3! Sample error:
    // >     main.cpp:49:12: error: invalid initialization of reference of type ‘uint8_t (&)[100] 
    // >     {aka unsigned char (&)[100]}’ from expression of type ‘uint8_t [10] {aka unsigned char [10]}’
    // >          foo2(a1);
    // >                 ^
    // foo2(a1);
    // foo2(a2);
    // foo2(a3);
    // ------------------
    // Works just fine for this one since the array `a4` has the right length!
    // Is `sizeof(array) = 100`
    uint8_t a4[100];
    foo2(a4);
    printf("\n");

    foo3(a1);
    foo3(a2);
    foo3(a3);
    foo3(a4);
    printf("\n");

    return 0;
}

Sample output:

(compiler warnings, referring to the sizeof call inside foo()):

main.cpp:26:49: warning: ‘sizeof’ on array function parameter ‘array’ will return size of ‘uint8_t* {aka unsigned char*}’ [-Wsizeof-array-argument]                               
main.cpp:23:27: note: declared here                                                                                                                                               

(stdout "standard output"):

Hello World                                                                                                                                                                       
                                                                                                                                                                                  
sizeof(array) = 8                                                                                                                                                                 
sizeof(array) = 8                                                                                                                                                                 
sizeof(array) = 8                                                                                                                                                                 
                                                                                                                                                                                  
sizeof(array) = 100                                                                                                                                                               
                                                                                                                                                                                  
sizeof(array) = 10                                                                                                                                                                
sizeof(array) = 11                                                                                                                                                                
sizeof(array) = 12                                                                                                                                                                
sizeof(array) = 100   

Shouldn't this work? for things like Arduino(AVR) c++ at least.

//rename func foo to foo_ then
#define foo(A) foo_(A, sizeof(A))

void foo_(char a[],int array_size){
...
}
Related