2

Possible Duplicates:
C++: sizeof for array length
Sizeof array passed as parameter

#include "stdafx.h"
#include <iostream>

using namespace std;

void PrintArrayLength(int arr[])
{
    cout << "Function Array length is: " << sizeof(arr)/sizeof(int) << endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
    int arr[] = {1, 2, 3};

    cout << "Array length is: " << sizeof(arr)/sizeof(int) << endl; // print 3

    PrintArrayLength(arr); // print 1
    return 0;
}

Why one place sizeof(arr)/sizeof(int) gives value of 1 and the other place gives value of 3?

Community
  • 1
  • 1
q0987
  • 34,938
  • 69
  • 242
  • 387
  • 1
    Many duplicates on SO already, e.g. [Sizeof array passed as parameter](http://stackoverflow.com/questions/1328223/sizeof-array-passed-as-parameter) – Paul R Apr 02 '11 at 15:18
  • 1
    @PaulR: Whilst there are indeed many duplicates, that isn't one of them. That question was about pointers to dynamically allocated blocks of memory, whereas this one is about the decay-to-pointer behaviour of passing arrays by value. The answers are the same, but the questions are not. – Lightness Races in Orbit Apr 02 '11 at 16:01
  • @Tomalak: are you sure we're looking at the same question ? I did update my comment after initially getting a bad example duplicate, but I think [Sizeof array passed as parameter](http://stackoverflow.com/questions/1328223/sizeof-array-passed-as-parameter) is certainly a valid duplicate. Either way, there are plenty to choose from. – Paul R Apr 02 '11 at 16:05
  • @PaulR: I was looking at your pre-edit comment. – Lightness Races in Orbit Apr 02 '11 at 17:03

2 Answers2

19

Because when you pass an array by value to a function, you're actually passing a pointer (to the first element of the array).

void PrintArrayLength(int arr[])
{
    cout << "Function Array length is: " << sizeof(arr)/sizeof(int) << endl;
}

is actually:

void PrintArrayLength(int* arr)
{
    cout << "Function Array length is: " << sizeof(arr)/sizeof(int) << endl;
}

Don't be misled by the syntactic sugar that lets you declare an array as int[]. In reality, there's no such type and what you've really written is:

int arr[3] = {1, 2, 3};

It's just that the compiler can trivially fill in that 3 for you from the initialiser.


As an aside, you can retain the dimensions if you pass your array by reference. For convenience, you can make use of templates so that you only need one function no matter what dimension the array has (as the dimension is part of the type):

template <size_t N>
void PrintArrayLength(int (&arr)[N])
{
    cout << "Function Array length is: " << sizeof(arr)/sizeof(int) << endl;
}

An extension to this is the good advice to not use sizeof. You can easily fall into the trap that you fell into, thinking that you're sizing up an array when, really, you're not. Use this instead:

template <typename T, size_t N>
size_t length_of_array(T (&)[N]) {
   return N;
}

Trying to use this function on anything but a proper array will fail with a compiler error, instead of silently giving misleading values like your code did.

Of course, replacing your use of raw arrays with objects of type boost::array (or std::array in C++0x) or even std::vector (which can be resized) is the best approach. :)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

Tomalak Geret'kal is right.

For the functionality you want you may use this:

void DoSomethingWithArray(int* arr, size_t n)
{
    cout << "Function Array length is: " << n << endl;
}

template< size_t n >
inline void DoSomethingWithArray(int (&arr)[n])
{
    // n == sizeof(arr)/sizeof(int)
    DoSomethingWithArray( arr, n );
}

I'm using function void DoSomethingWithArray(int* arr, size_t n) instead of writing the code directly inside of the function template's body because if the function's body is big enough it would be a waste of resources to instantiate separate function (specialized from function template) for each size of array n ever used in pogram.

Serge Dundich
  • 4,221
  • 2
  • 21
  • 16
  • It's a balance. The extra code may _not_ be worse than a whole new stack frame. Depends on the use case. – Lightness Races in Orbit Apr 02 '11 at 16:00
  • @Tomalak Geret'kal: Well of course I don't consider creating extra stack frame as a good option. I obviously rely on inlining single function call directly instead of instantiating a function per array size value - sane compiler would always do that if optimization is turned on. And even without optimization instantiating small functions with a single call or any other small action (per n value) is OK but if the function is big it is just unacceptable. – Serge Dundich Apr 03 '11 at 21:35
  • Good point; I had forgotten about that! – Lightness Races in Orbit Apr 03 '11 at 21:52