user13992743
user13992743

Reputation:

how can i check array length in a function?

In my file I have created function length that must return length of auto type array, but instead of right answer it everytime returns 1.

#include <iostream>
using namespace std;

int length(auto arr){
    return sizeof(arr) / sizeof(*arr);
}

int main(){
    int arr[] = {1,2,3,4,5,0};
    // Test
    cout << length(arr); // it returns 1 but the right answer is 6
    return 0;
}

Upvotes: 0

Views: 109

Answers (4)

Peter
Peter

Reputation: 36597

The fact your code compiles at all is because your compiler (gcc?) supports a non-standard extension.

You would be better off using standard containers (e.g. std::vector<int> if the size is determined at run time, or std::array<int, 6> if the size is fixed at compile time).

But, for a function that takes a raw array and gives its size, you can simply pass a reference;

 int length(const auto &arg) {return sizeof(arr)/sizeof(*arr);}

or

 template<int N> int length(const int (&arr)[N])
 {
     return N;
 }

Depending on your needs, the function can also be made constexpr and noexcept.

In C++17 and later, simply use the helper function std::size() (supplied in various standard headers, such as <iterator>, and works with a raw array as well as standard containers)

int main(){
    int arr[] = {1,2,3,4,5,0};
    cout << std::size(arr); 
    return 0;
}

Upvotes: 0

HolyBlackCat
HolyBlackCat

Reputation: 96053

It's impossible to pass an array to a function directly (by value, that is), attempting to do so passes a pointer to its first element instead. Other answers have already explained this.

What you can do is pass a reference:

int length(const auto &arr)
{
    return sizeof(arr) / sizeof(*arr);
}

This works for arrays, but gives wrong results for pointers, standard containers, etc.

To make it more bullet-proof, you can rewrite it to make it accept references to arrays only:

template <typename T, std::size_t N>
std::size_t length(const T (&)[N])
{
    return N;
}

But we already have a standard function that does exactly this, it's called std::size. And it's also overloaded to work with containers.

Upvotes: 0

prog-fh
prog-fh

Reputation: 16805

You are using a C-style array, and this type cannot be copied. If we assume that your compiler has a version that supports auto parameters, it's like if it had a template parameter that would be deduced to int * here, because instead of being copied, a C-style array decays to int *.

In this case, sizeof(arr) is sizeof(int *) which is probably 4 on a 32-bit system or 8 on a 64-bit system. sizeof(*arr) is sizeof(int) and is probably 4 on most systems. Thus sizeof(arr)/sizeof(arr[0]) in length() will probably always give 1 or 2.

If you want such a function returning the number of elements of an array, you could use the std::array() type as many comments suggest.

An alternative is to provide a template function that is aware of the constant (known at compile time) size of the array.

/**
  g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
      -pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
      -g -O0 -UNDEBUG -fsanitize=address,undefined
**/

#include <iostream>

template<typename T,
         int N>
int
length([[maybe_unused]] const T(&arr)[N])
{
  return N;
}

int 
main()
{
  int arr[] = {1,2,3,4,5,0};
  std::cout << length(arr) << '\n'; 
  return 0;
}

Upvotes: 1

id01
id01

Reputation: 1587

Ah yes, you've fallen victim to the classic array decay problem.

When have a function that takes in an array, C passes it as a pointer, because "array" isn't a passable data type. You get 1 because sizeof(arr) == sizeof(size_t) == sizeof(*arr) == sizeof(int), so sizeof(arr) / sizeof(*arr) == 1.

Unfortunately, there is no way to find the length of C-style arrays in a subfunction. However, some things you can do:

  1. You can pass the length into the function as well. Unfortunately, this is pretty self-defeating if you want a length function. However, it's used for many C-style applications which need to support null bytes.

  2. You can use the C++ style std::array, which allows you to find the size of the array with size(). This allows you to create an array without having to play with C shenanigans. You can also use std::vector, which is variable-size instead of fixed-size.

Upvotes: 0

Related Questions