How to reliably get size of C-style array?

2019-01-07 22:46发布

How do I reliably get the size of a C-style array? The method often recommended seems to be to use sizeof, but it doesn't work in the foo function, where x is passed in:

#include <iostream>

void foo(int x[]) {
  std::cerr << (sizeof(x) / sizeof(int)); // 2  
}

int main(){
    int x[] = {1,2,3,4,5};
    std::cerr << (sizeof(x) / sizeof(int)); // 5                              
    foo(x);
    return 0;
}

Answers to this question recommend sizeof but they don't say that it (apparently?) doesn't work if you pass the array around. So, do I have to use a sentinel instead? (I don't think the users of my foo function can always be trusted to put a sentinel at the end. Of course, I could use std::vector, but then I don't get the nice shorthand syntax {1,2,3,4,5}.)

标签: c++ c arrays size
9条回答
你好瞎i
2楼-- · 2019-01-07 23:26

You can either pass the size around, use a sentinel or even better use std::vector. Even though std::vector lacks initializer lists it is still easy to construct a vector with a set of elements (although not quite as nice)

static const int arr[] = {1,2,3,4,5};
vector<int> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) );

The std::vector class also makes making mistakes far harder, which is worth its weight in gold. Another bonus is that all C++ should be familiar with it and most C++ applications should be using a std::vector rather than a raw C array.

As a quick note, C++0x adds Initializer lists

std::vector<int> v = {1, 2, 3, 4};

You can also use Boost.Assign to do the same thing although the syntax is a bit more convoluted.

std::vector<int> v = boost::assign::list_of(1)(2)(3)(4);

or

std::vector<int> v;
v += 1, 2, 3, 4;
查看更多
ら.Afraid
3楼-- · 2019-01-07 23:31

I also agree that Corwin's method above is very good.

template <int N>
void foo(int (&x)[N]) 
{
    std::cerr << N;
}

I don't think anybody gave a really good reason why this is not a good idea.
In java, for example, we can write things like:

int numbers [] = {1, 2, 3, 4};
for(int i = 0; i < numbers.length(); i++)
{
   System.out.println(numbers[i]+"\n");
}

In C++ it would be nice instead of saying

int numbers [] = {1, 2, 3, 4};
int size = sizeof(numbers)/sizeof(int);
for(int i = 0; i < size; i++)
{
    cout << numbers[i] << endl;
}

We could take it a step further and go

template <int N>
int size(int (&X)[N])
{
   return N;
}

Or if that causes problems I suppose you could write explicitly:

template < int N >
int size(int (&X)[N])
{
   int value = (sizeof(X)/sizeof(X[0]));
   return value;
}

Then we just have to go in main:

int numbers [] = {1, 2, 3, 4};
for(int i = 0; i < size(numbers); i++)
{
   cout << numbers[i] << endl;
}

makes sense to me :-)

查看更多
\"骚年 ilove
4楼-- · 2019-01-07 23:32

In C array parameters in C are really just pointers so sizeof() won't work. You either need to pass in the size as another parameter or use a sentinel - whichever is most appropriate for your design.

Some other options:

Some other info:

  • for C++, instead of passing a raw array pointer, you might want to have the parameter use something that wraps the array in a class template that keeps track of the array size and provides methods to copy data into the array in a safe manner. Something like STLSoft's array_proxy template or Boost's boost::array might help. I've used an array_proxy template to nice effect before. Inside the function using the parameter, you get std::vector like operations, but the caller of the function can be using a simple C array. There's no copying of the array - the array_proxy template takes care of packaging the array pointer and the array's size nearly automatically.

  • a macro to use in C for determining the number of elements in an array (for when sizeof() might help - ie., you're not dealing with a simple pointer): Is there a standard function in C that would return the length of an array?

查看更多
登录 后发表回答