Search code examples
c++arraysfor-loopsizeof

Why does sizeof(array) return three times more than indexes in the array?


I wanted to print an array in a for loop, but not only the array prints random numbers, but also prints 3 times more numbers than the boundaries of the array, which is weird since i am using sizeof(A) so it only prints until the bounds of it. Would you guys know why it prints several more times than specified in the code?

the code I tried is as follows:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{
        int A[] = {1, 2, 4, 8, 16, 32, 64, 128};
        for (int i = 0; i < sizeof(A); i++) {
                cout << A[i] << endl;
        }
}

The output is as follows:

1 2 4 8 16 32 64 128 14294328 0 14294384 11 14294320 0 794104558 32759 0 0 62 0 794128456 32759 0 0 0 0 0 0 0 0 0 0

As you can see, there are 32 outputs when the amount of prints was supposed to be only the amount as the size of the array.

The output I was hoping for with the code is: 1 2 4 8 16 32 64 128


Solution

  • The expression with the sizeof operator sizeof(A) yields the size in bytes of the array A. The obtained value is equal to the number of elements in the array multiplied by the size of element of the array that is

    sizeof( A ) = 8 * sizeof( int )
    

    So if you have an array size and know the type of elements of the array you can get the number of elements in the array like

    size_t n = sizeof( A ) / sizeof( A[0] )
    

    It means that your for loop should be rewritten like

    for ( size_t i = 0, n = sizeof( A ) / sizeof( A[0] ); i < n; i++ ) {
    //...
    

    From the C++17 Standard (8.3.3 Sizeof)

    1 The sizeof operator yields the number of bytes in the object representation of its operand. The operand is either an expression, which is an unevaluated operand (Clause 8), or a parenthesized type-id. The sizeof operator shall not be applied to an expression that has function or incomplete type, to the parenthesized name of such types, or to a glvalue that designates a bit-field. sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1. The result of sizeof applied to any other fundamental type (6.9.1) is implementation-defined. [ Note: In particular, sizeof(bool), sizeof(char16_t), sizeof(char32_t), and sizeof(wchar_t) are implementation-defined.

    Pay attention to that there is standard C++ function std::size() declared in header <iterator> that can be use instead of the expression with the sizeof operator

    #include <iterator>
    
    //...
    
    for ( size_t i = 0, n = std::size( A ); i < n; i++ ) {
    //...
    

    But before introducing the standard C++ function std::size there was used data member value of structure std::extent declared in header <type_traits>.

    Another approach is to use range-based for loop like

    for ( const auto &item : A ) {
            cout << item << endl;
    }
    

    Also you could use iterators in the for loop or a standard algorithm like std::copy or std::for_each.

    Here is a demonstration program that shows possible ways to output an array

    #include <iostream>
    #include <type_traits>
    #include <iterator>
    #include <algorithm>
    
    int main()
    {
        int A[] = { 1, 2, 4, 8, 16, 32, 64, 128 };
    
        //  using the sizeof operator
        for (size_t i = 0, n = sizeof( A ) / sizeof( A[0] ); i < n; i++)
        {
            std::cout << A[i] << ' ';
        }
        std::cout << '\n';
    
        //  using function std::size()
        for (size_t i = 0, n = std::size( A ); i < n; i++)
        {
            std::cout << A[i] << ' ';
        }
        std::cout << '\n';
    
        //  using std::extent_v
        for (size_t i = 0, n = std::extent_v<decltype( A )>; i < n; i++)
        {
            std::cout << A[i] << ' ';
        }
        std::cout << '\n';
    
        //  using range-based for loop
        for ( const auto &item : A )
        {
            std::cout << item << ' ';
        }
        std::cout << '\n';
    
        //  using for loop with iterators
        for (auto first = std::begin( A ), last = std::end( A ); first != last; ++first)
        {
            std::cout << *first << ' ';
        }
        std::cout << '\n';
    
        //  using algorithm std::copy
        std::copy( std::begin( A ), std::end( A ),
            std::ostream_iterator<int>( std::cout, " "));
        std::cout << '\n';
    
        //  using algorithm std::for_each
        std::for_each( std::begin( A ), std::end( A ),
            []( const auto &item )
            {
                std::cout << item << ' ';
            } );
        std::cout << '\n';
    
    }
    

    The program output is

    1 2 4 8 16 32 64 128 
    1 2 4 8 16 32 64 128 
    1 2 4 8 16 32 64 128 
    1 2 4 8 16 32 64 128 
    1 2 4 8 16 32 64 128 
    1 2 4 8 16 32 64 128 
    1 2 4 8 16 32 64 128