How to reliably get size of C-style array?

后端 未结 10 1962
广开言路
广开言路 2020-11-29 09:37

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

相关标签:
10条回答
  • 2020-11-29 10:02

    A common idiom mentioned in GNU Libstdc++ documentation is the lengthof function:

    template<typename T, unsigned int sz>
    inline unsigned int lengthof(T (&)[sz]) { return sz; }
    

    You can use it as

    int x[] = {1,2,3,4,5};
    std::cerr << lengthof(x) << std::endl;
    

    Warning: this will work only when the array has not decayed into a pointer.

    0 讨论(0)
  • 2020-11-29 10:03

    Now, you can use C++11's extent and rank.

    By example:

    #include <iostream>
    #include <type_traits>
    
    int main()
    {
      int a[][3] = {{1, 2, 3}, {4, 5, 6}};
    
      std::cout << "\nRank:           : " << std::rank<decltype(a)>::value;
      std::cout << "\nSize: [_here_][]: " << std::extent<decltype(a), 0>::value;
      std::cout << "\nSize: [][_here_]: " << std::extent<decltype(a), 1>::value;
      std::cout << "\nSize: [][]_here_: " << std::extent<decltype(a), 2>::value;
    }
    

    prints:

    Rank:           : 2
    Size: [_here_][]: 2
    Size: [][_here_]: 3
    Size: [][]_here_: 0
    
    0 讨论(0)
  • 2020-11-29 10:04

    How about this?..

    template <int N>
    void foo(int (&x)[N]) {
        std::cerr << N;
    }
    0 讨论(0)
  • 2020-11-29 10:08

    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?

    0 讨论(0)
  • 2020-11-29 10:08

    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;
    
    0 讨论(0)
  • 2020-11-29 10:09

    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 :-)

    0 讨论(0)
提交回复
热议问题