Search code examples
c++arrayspass-by-referenceimplicit-conversionpass-by-value

Why is my array being passed with an incorrect size?


I am just starting to learn C++ and I was playing around with functions. I am trying to pass an integer array as a parameter, and have the function print every element of the array. My issue however is that I have an array initialized to a seize of 10, but when I pass it to the function it only reads it as a size of 2. Any help would be appreciated! You can find my program below.

#include <iostream>
#include <cmath>

using namespace std;

void Max(int Arr[])
{
    for (int i=0; i<sizeof(Arr)/sizeof(Arr[0]); i++)
    {
        cout<< Arr[i]<<endl;
    }
}


int main()
{
    int Arr[]={1,2,3,4,5,6,7,8,9,10};

    Max(Arr);

    return 0;
} 

Thank you all for the help in advance!


Solution

  • When an array is passed by value it is implicitly converted to pointer to its first element.

    On the other hand a function parameter declared as having an array type is adjusted by the compiler to pointer to the array element type.

    So for example these function declarations

    void Max(int Arr[]);
    void Max(int Arr[1])
    void Max(int Arr[10])
    void Max(int Arr[100]);
    

    declare the same function and are adjusted by the compiler to the declaration

    void Max( int *Arr );
    

    As a result within the function the parameter Arr is a pointer and this expression

    sizeof(Arr)/sizeof(Arr[0])
    

    is equivalent to

    sizeof( int * ) / sizeof( int )
    

    that yields either 1 or 2 depending on the size of the type int *.

    When you passing an array by value to a function you should also pass its size explicitly.

    So the function could be defined like

    void Max( const int Arr[], size_t n )
    {
        for ( size_t i = 0; i < n; i++ )
        {
            cout << Arr[i] << endl;
        }
    }
    

    And the function can be called like

    Max(Arr, sizeof( Arr ) / sizeof( *Arr ) );
    

    Another approach is to declare the function parameter as having a referenced type. In this case it is better to use a template function that it could be called for an array at least of any size.

    template <size_t N>
    void Max( const int ( &Arr )[N] )
    {
        for ( size_t i = 0; i < N; i++ )
        {
            cout << Arr[i] << endl;
        }
    }
    

    Or the function could be defined like

    template <typename T, size_t N>
    void Max( const T ( &Arr )[N] )
    {
        for ( size_t i = 0; i < N; i++ )
        {
            cout << Arr[i] << endl;
        }
    }
    

    And the both functions can be called like

    Max(Arr);
    

    Pay attention to that you could use the standard class template std::array declared in the header <array>. For example

    #include <iostream>
    #include <array>
    
    const size_t N = 10;
    
    std::ostream & Max( const std::array<int, N> &a, std::ostream &os = std::cout )
    {
        for ( const auto &item : a )
        {
            os << item << ' ';
        }
    
        return os;
    }
    
    
    int main()
    {
        std::array<int, N> a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    
        Max( a ) << '\n';
    
        return 0;
    } 
    

    The program output is

    1 2 3 4 5 6 7 8 9 10