1

I'm trying to get the length of an array passed as a parameter on some function. The code is look like this :

double getAverage(int numbers[])
{
    int length = sizeof(numbers)/sizeof(numbers[0]);
    // here the result of the length is 1.
    int sum = 0;
    for (int i = 0 ; i < length ; i++)
    {
        sum += numbers[i];
    }
    return (double)sum / length;
}

int main()
{
    int numbers[8] = {1,2,3,4,5,6,7,8};
    //if I call here sizeof(numbers)/sizeof(numbers[0] the result will be 8 as it   
    //should be.
    cout << getAverage(numbers) << endl;
    return 0;
}

My question is how to get the array length which is passed as argument of a function by reference(although I know that every array is passed by reference)? I know that there is a lot of questions about finding the array length in C/C++ but no one of them give me the answer which I'm looking for. Thanks in advance.

Jordan Borisov
  • 1,603
  • 6
  • 34
  • 69

9 Answers9

6

You will have to explicitly pass the length of the array as an parameter to the function.

What you pass to the function is just an pointer to the array, not the array itself, so there is no way to determine the length of the array inside the function unless you explicitly pass the length as an function parameter.

You can probably use std::vector, which provides member functions to get no of elements in the vector, using std::vector::size(), that is the best you can do there is no way to do so using c-style arrays.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • yes I know but this is not the way which I'm looking for. Something like in Java. just declare an array and get it length : int[] arr = new int[5]; arr.length; – Jordan Borisov Jan 30 '12 at 09:47
  • @JordanBorisov: if you are looking for an answer like "int length = numbers.len()" then i have bad news for you. The only way to get such thing is to code an Array class yourself, or use a similar existing solution. Or another language. – PeterK Jan 30 '12 at 09:50
  • 1
    @JordanBorisov: My answer summarizes it.There is no way you can do so using c-style arrays.Your best can be using `std::vector`. – Alok Save Jan 30 '12 at 09:52
  • @Als: Having a reference parameter and deducing the size of the array by template argument deduction will do the job. – Prasoon Saurav Jan 30 '12 at 11:25
4

Arrays decay to pointers when passing them as parameters. You can't retrieve size information inside the function.

Why aren't you using std::vector? It's the c++ way.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
3

At run-time, there is no information associated with an array that tells you its length. The array pretty much "decays" into just the address of the first element.

At compile-time, the length is part of the type, so if you declare your function to take e.g. int numbers[8] you can get the length using the sizeof expression you mention.

Of course, this means you can only validly call the function with arrays of length 8, which kind of makes it a bit useless.

Thus, the only way around this is to explicitly add information at run-time about the array's length, by adding a second size_t length argument to the function.

In C++, you could also use templates to have the compiler create specialized versions of the function for each array length, but that is kind of wasteful.

As pointed out by others, you can also "level up" your abstraction and use e.g. std::vector<int> to get a size() method. That is of course pretty much the same thing, the vector container adds run-time information about the number of elements.

This might not be "the answer which you're looking for", I'm sorry about that.

unwind
  • 391,730
  • 64
  • 469
  • 606
2

If you must use an array, you could 'templatize' your function:

template <size_t length> double getAverage(int (&numbers)[length]) {
    int sum = 0;
    for (int i = 0 ; i < length ; i++)
    {
        sum += numbers[i];
    }
    return (double)sum / length;
} 
aligray
  • 2,812
  • 4
  • 26
  • 35
  • What's the purpose of the `length` variable when you already have the `N` constant? – fredoverflow Jan 30 '12 at 10:25
  • 2
    You could simply rename `N` to `length` then :) – fredoverflow Jan 30 '12 at 10:39
  • Note that if the function is large, it might be worth implementing it as a function that takes the length as argument (or that takes teo iteratorstyle pointers) and then a template (wrapper or helper) to obtain the size (or pointers), as that will reduce the generated code size. – David Rodríguez - dribeas Jan 30 '12 at 13:01
1

You have to pass in the length as a parameter, or use std::vector which "contains" the length. You can access it with the size() method.

Andre
  • 1,577
  • 1
  • 13
  • 25
1

Or use std::vector (instead of int[]) which provides a size() function

TheMathemagician
  • 968
  • 9
  • 21
1

You can use std::vector, or std::list as all have give. But if you are adamant that you want to use an int[] without a second argument, then you can insert a code number as the last element of the array. that way you can know the end.... Or u can save the length of the array in its first element and use the rest normally.

Prasanth Madhavan
  • 12,657
  • 15
  • 62
  • 94
1

You can pass an array by reference in which case the areay size has to be specified. However, the size of a statically sized array can be deduced for a template argument:

template <int Size>
double getAverage(int (&numbers)[Size]) { ... }

The only problem with this approach is that it creates a new instantiation for each array size. Of course, the fix to this is to actually pass begin and end iterators to the function doing the actual work. The iterators can easily be determined using begin() and end() functions using the trick above. The code would look something like this:

double average
    = std::accumulate(begin(numbers), end(numbers), 0.0)
    / std::distance(begin(numbers), end(numbers));
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • +1 Note that while the accumulate/distance code might look as iterating over the array twice, tha distance of two pointers is a constant expression. – David Rodríguez - dribeas Jan 30 '12 at 13:07
  • Well, it is a constant _time_ expression: a _constant expression_ is a compile-time thing in C++ and this it is probably not, although it could be. The main reason to use this formulation is that actually works for any non-empty container although e.g. for a list it would iterate twice over the list. The latter is a goid reason why it would be good to have versions of the algorithms taking ranges. – Dietmar Kühl Jan 30 '12 at 14:25
  • Right, that's the problem with writing with on a phone :) I meant constant-time expression. – David Rodríguez - dribeas Jan 30 '12 at 19:43
0

You can use templates:

template<std::size_t Length>
double getAverage(int (&numbers)[Length])
{
...
}

but this may lead to code bloat as the compiler will create this for every new array size you pass in. You might be better off combining a template with a parameter

template<typename T, std::size_t Length>
std::size_t GetCount(T (&numbers)[Length])
{
    return Length;
}

[main]

getAverage(numbers, GetCount(numbers));
DanDan
  • 10,462
  • 8
  • 53
  • 69