0

So my C++ instructor told us in class that there was no function to determine an array size in C++ and I was not satisfied with that. I found a question here on stackoverflow that gave this bit of code (sizeof(array)/sizeof(*array)) and while I don't exactly understand it, I understand it takes the total amount of memory allocated to the array and divides it by what I assume is the default memory allocation of its data type...(???) I decided I wanted to practice writing functions (I'm in CS 111 - Fundamentals 1) and write a function that returned the number of elements in any array I passed it. This is what I wrote:

#include <iostream>
using namespace std;

int length_of_array(int some_list[])
{
    // This only returns the integer 1 for some reason
   return (sizeof(some_list)/sizeof(*some_list));
}

int main()
{
    // Declare and initialize an array with 15 elements
    int num_list[] = {2,4,6,8,10,12,14,16,18,20,22,24,26,28,30};

    //Outputs what I assume is the total size in bytes of the array
    cout << sizeof(num_list) << endl;

    //Outputs what I assume to be size of memory set aside for each in element in an array
    cout << sizeof(*num_list) << endl;

    //This extrapolates array's number of elements
    cout << "This is the output from direct coding in the\nint main function:\n" <<
            (sizeof(num_list)/sizeof(*num_list)) << endl;

    //This function should return the value 15 but does not
    int length = length_of_array(num_list);

    cout << "This is the length of the array determined\n";
    cout << "by the length_of_array function:\n"  << length << endl;



    return 0;
}

The function returns 1 no matter what I do. Would somebody please give me a C++ specific workaround and explanation of how it works? Thank you.

Sinux1
  • 93
  • 5
  • 11
  • C functions can't actually take arguments as arrays. Arrays instead *decay* into pointers when passed to functions. See http://www.c-faq.com/aryptr/ – jamesdlin Apr 10 '16 at 04:32
  • This is not exactly a duplicate of that question. That one is about C, this one is about C++. And as the answer here shows, there is an important difference. You can't use that template trick in C. So I'm voting to reopen. – Sergei Tachenov Apr 10 '16 at 04:46
  • So if it has a completely different answer, how is it a duplicate - can the accepted answer apply to the question you're saying I duplicated? – Sinux1 Apr 10 '16 at 04:50
  • duplicate: http://stackoverflow.com/questions/968001/determine-size-of-array-if-passed-to-function – M.M Apr 10 '16 at 08:19

1 Answers1

5

The problem is here:

int length_of_array(int some_list[]);

Basically, whenever you pass an array as the argument of a function, no matter if you pass it like int arr[] or int arr[42], the array decays to a pointer (with ONE EXCEPTION, see below), so the signature above is equivalent to

int length_of_array(int* some_list);

So of course when doing sizeof(some_list)/sizeof(*some_list) you will get the ratio between the size of the pointer the array decayed to and the size of the type representing the first element. In your case, 1, as it looks like on your machine the size of a pointer is probably 4 bytes (32 bits), same as the size of an int.

So my C++ instructor told us in class that there was no function to determine an array size in C++ and I was not satisfied with that.

YOUR TEACHER IS WRONG! There is a way of passing an array by reference and getting its size:

template<size_t N>
int length_of_array(int (&arr)[N])
{
    std::cout << N << std::endl; // WORKS!
    return N;
}
vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • This is not exactly wrong. There is no *function* to determine an array size. You might have found a *way* to do it, but even then it won't work for dynamically-allocated arrays. But anyway, a nice trick. I wonder why it doesn't work with no reference? Because it decays to a pointer anyway even though you declare its size explicitly? – Sergei Tachenov Apr 10 '16 at 04:41
  • @SergeyTachenov Technically you're right, although I'm pretty sure that the teacher meant that no matter how you pass the array, you can't get its size. When passing it by reference, the function actually uses the exact *type* of the argument, which is `int [N]` in this case. For example, if you get rid of the template, but just do `void f(int (&arr)[10])`, then you won't be able to pass arrays of size different from `10`. Using a template is a bit nicer since it allows to detect `N`. – vsoftco Apr 10 '16 at 04:44
  • 1
    @disk_Error Arrays are a bit tricky in C and C++. They are strong types, in other words, `int arr1[10]` and `int arr2[20]` represent two different incompatible types. But, when passing an array by value to a function, the array decays to a pointer, so the type information is "erased" and simply becomes a pointer. The exception is when passing by reference. `int (&arr)[10]` means that `arr` is a reference to an `int [10]` array. In my code I used a template so you'll be able to pass any size (the compiler will deduce `N` since knows the full type of the array). – vsoftco Apr 10 '16 at 04:48
  • @SergeyTachenov And yes, if you don't pass by reference, then the type simply decays to a pointer. I believe the original motivation of why this is so came from `C`, where efficiency was of paramount importance at that time (and still is) so copying arrays was not desirable. – vsoftco Apr 10 '16 at 04:52
  • @vsoftco Thank you. I have a lot more reading of my textbook it seems. We haven't actually gone over pointers yet. We just barely finished what an array is... I just have an inquisitive mind. When I learn of a new concept for some reason my first instinct is to test the boundaries. Thanks again – Sinux1 Apr 10 '16 at 04:56
  • Something to keep in mind is that the sizeof() operator is resolved at compile time. Templates are, too. There's a reason why C memory functions like memcpy take a pointer as one argument, and the length of the buffer as another. In C++, a vector encapsulates this - a dynamic array, that's contiguous in memory, and with a length property. – eoD .J Apr 10 '16 at 05:31
  • Coming back to my own question after I have graduated and work as a full time software engineer is.... surreal. – Sinux1 Mar 28 '23 at 21:32