c++arrays

Getting the size of an array in C++


Today I saw this code on Leetcode:

#include <iostream>

int main() {
    int a1[5] = {1, 2, 3};  // other element will be set as the default value
    int size = sizeof(a1) / sizeof(*a1);
    cout << "The size of a1 is: " << size << endl;
}

As I don't really grasp the idea of pointers yet, can someone help me understand what's going on?

What's the difference with:

#include <iostream>
using namespace std;

int main() {
  int myNumbers[5] = {10, 20, 30, 40, 50};
  int getArrayLength = sizeof(myNumbers) / sizeof(myNumbers[0]);
  cout << getArrayLength;
  return 0;
}

Or using end & begin:

#include<iostream>    
#include<array> 
using namespace std;
int main()
{  
   //Given Array
   int arr[] = { 11, 22, 33, 44 };
   
   cout<<"The Length of the Array is : "<<end(arr)-begin(arr); //length
   
   return 0;
}

Why are there many forms of finding something as basic as the length of an array in C++?


Solution

  • Arrays in C and C++ have many of the same behaviors as pointers and is the source of a lot of confusion in these languages.

    Consider the following:

    int a1[5] = {1, 2, 3, 4, 5};
    
    // array offset by zero is just a pointer to the first element
    int* a1_0 = a1 + 0;  // 1
    
    // This would also be equivalent to the above
    int* a1_0 = a1;      // 2
    
    // And this would be the second element in the array
    int* a1_1 = a1 + 1;
    

    1/2 show how there is an equivalence between the array and a pointer to the first element in the array. *a1 is dereferencing the array, which since the array is equivalent (in some sense) to a pointer to the first element of the array, is equivalent to a1[0].

    When calculating the size of the array, both of these are doing the same thing:

    int size = sizeof(a1) / sizeof(*a1);
    int size = sizeof(a1) / sizeof(a1[0]);
    

    C++ has a concept of "iterators" which is intended to provide a uniform interface to many different container types (arrays, std::vector, std::list, etc.). The begin/end functions (introduced in C++11) are part of the iterator interface. However, in the case arrays, they are just returning pointers:

    int a1[5] = {1, 2, 3};
    assert(a1       == begin(a1));
    assert((a1 + 5) == end(a1));
    

    So using them to get the size of the array is really just getting the difference between pointers:

    int a1[5] = {1, 2, 3};
    int* first_element = a1;
    int* after_last_element = a1 + 5; // Note this is not an element in the array
    int size = after_last_element - first_element;
    int size = end(a1) - begin(a1);
    

    In C++, there is a simpler way to get the size of an array though - std::size (introduced in C++17):

    int a1[5] = {1, 2, 3};
    int size = std::size(a1);
    

    However, C++ programmers will generally recommend that you use std::array instead of raw "c-style" arrays. They provide more safety and convenience than c-style arrays and integrate more cleanly into the rest of the C++ standard library. Using std::array would look something like:

    std::array<int, 5> a1 = {1, 2, 3, 4, 5};
    int size = a1.size();
    

    As far as WHY all of these things exist: These different techniques can be used in many situations beyond just getting the size of an array. If all we needed was the size of an array, it would be non-sense to have all these different techniques. However, each of these techniques has a unique capability that they provide. This is not unusual in programming. There are always many ways to solve even the simplest of problems.