如何确定传递的数组是1维、2维还是N维数组

3
我想编写一个函数,该函数将接受一个数组作为输入参数。该函数应打印出数组的所有元素。
print_array(arr)
{
  //print all the elemnts of arr.
}

我不知道如何做到那一点。

我认为首先我们需要找出传递的数组是一维、二维还是三维等等……的数组。

因为,要打印以下元素:

                            1-D array, you need only 1 for loop.
                            2-D array, you need only 2 for loop.
                            3-D array, you need only 3 for loop.

不过我不知道您如何确定它是一维、二维还是N维数组。请帮忙。


将函数签名修改为以下形式如何:print_array(type *array, int n_dimensions, int *dimensions) - eq-
我无法将维度作为参数传递给函数。该函数只接受数组的基地址作为输入。而且,由函数开发人员来确定它是1-D、2-D还是3-D数组...并根据此打印出所有元素。 - Jatin
2
@VikasChhipa:一旦数组被转换为指针,就无法恢复该信息。唯一的选择是将维度传递给函数,或者像eq-'s答案中那样传递对数组的引用而不转换为指针。 - Mike Seymour
gslices是使用C++表示多维数组的标准方式。http://www.cplusplus.com/reference/std/valarray/gslice/ - Josh Petitt
5个回答

16

使用C++11的std::rank类型特征,您可以轻松找出确切的维数,只需一个重载即可:

#include <type_traits>
#include <iostream>

template<class T, unsigned N>
void print_dimensions(T (&)[N]){
  static unsigned const dims = std::rank<T>::value + 1;
  std::cout << "It's a " << dims << "-D array, you need "
            << dims << " for-loops\n";
}

然而,你实际上不需要使用std::rank来打印所有元素;这可以通过一个简单的重载函数轻松解决:
namespace print_array_detail{
template<class T>
void print(T const& v){ std::cout << v << " "; }
template<class T, unsigned N>
void print(T (&arr)[N]){
  for(unsigned i=0; i < N; ++i)
    print(arr[i]);
  std::cout << "\n";
}
}

template<class T, unsigned N>
void print_array(T (&arr)[N]){ print_array_detail::print(arr); }

演示例子。


在C++03中,使用Boost.TypeTraits中的boost::rank - ecatmur
@ecatmur:或者你可以自己编写,cppreference上甚至有一个示例实现。 :) - Xeo
@Xeo:谢谢,兄弟...它正在工作。由于我对模板不熟悉...我不理解print_array(T (&arr)[N])的含义...但我会自己尝试理解它 :-) - Jatin
@VikasChhipa:这是对数组的引用。编译器从传递的参数中推断出数组元素(T)的类型以及数组的大小(N)。 - Xeo
@Xeo:嗨,我在想为什么我们需要在函数“print_array(T(&arr)[N]){}”中注意(N)?因为...在这个函数内部,你只是调用“print_array_detail :: print(arr);”,这意味着你没有使用(N)...那么为什么我们需要取N?? - Jatin
显示剩余3条评论

4
通过C++中的模板和重载,您可以实现这个目标。考虑:
template<size_t X, size_t Y>
int sum_array_dimensions(int (&arr)[X][Y])
{
  // it's 2d
  return X + Y;
}

template<size_t X, size_t Y, size_t Z>
int sum_array_dimensions(int (&arr)[X][Y][Z])
{
  // it's 3d
  return X + Y + Z;
}

4
你可以在参数中编码维度数量,并传递一维数组。
#define N1 10
#define N2 100
void function(unsigned dimensions, int* array)
{ switch(dimension):
  { case 1:
      for (int i=0;i<N;i++)
      { ... array[i] ...
      }
      break;
    case 2:
      for (int i=0;i<N;i++)
      { for (int j=0;j<N;j++)
        { ... array[i*N+j] ...
        }
      }
      break;
    case 3:
      for (int i=0;i<N;i++)
      { for (int j=0;j<N;j++)
        { for (int k=0;k<N;k++)
          { ... array[i*N2+j*N+k] ...
          }
        }
      }
      break;
  }
}

如果N是2的幂,您可以使用左移<<x*2^n == x<<n)来优化乘法。
编辑 扩展解决方案

// the array is 0-indexed
void function(unsigned* dimensions, int* array)
{ //dimensions[0] = number of dimensions
  //dimensions[1 ... dimensions[0] ] the dimensions themselves
  for(int i=1,n=1;i<=dimensions[0];i++)
  { n*=dimensions[i]; }
  /* if the order in the array happens to be the wanted one */
  for(int i=1;i<=n;i++)
  { print( array[i] );
  }
  /* otherwise the dimensions are specified in the dimension array */
  for(int i=1;i<=n;i++)
  { int k=0;
    int temp=i;
    int base=1;       
    for(int j=1;j<=dimensions[0];j++)
    { k+=(temp%dimension[j])*base;
      base*=dimension[j];
      temp/=dimension[j];
    }
    print(array[k]);
  }   
  */

1
如果维度顺序不是默认顺序,则需要嵌套循环。在编辑的示例中,我用维度的for循环替换了嵌套循环。(最初我不想包含扩展示例,因为OP已经找到了令人满意的答案) - titus

3

正如其他人所说,当你将数组传递给函数时(除非你按引用传递),数组的大小会丢失。因此,您可以这样做:

/* this function does the work */
template <typename T>
void bar(T* arr, size_t n_dims, size_t* sizes)
{
    std::cout << n_dims << " dimension(s)\n";
    for (size_t i = 0; i < n_dims; ++i)   // for each dimension
        for (size_t j = 0; j < sizes[i]; ++j) ; // for each element
}

/* These are helper overloads to call bar with correct arguments. */
/* You'll need to provide one for each number of dimension you want to support */

template<typename T, size_t N>
void foo(T (&arr)[N])
{
    size_t sizes[] = {N};
    bar(arr, 1, sizes);
}

template<typename T, size_t N, size_t M>
void foo(T (&arr)[N][M])
{
    size_t sizes[] = {N, M};
    bar(arr, 2, sizes);
}

template<typename T, size_t N, size_t M, size_t O>
void foo(T (&arr)[N][M][O])
{
    size_t sizes[] = {N, M, O};
    bar(arr, 3, sizes);
}

int main()
{
    int arr1[42];
    int arr2[2][2];
    int arr3[2][3][4];
    foo(arr1);
    foo(arr2);
    foo(arr3);
}

Live example.


1

你不能这样做。但是你可以用相同的名称编写3个不同的函数,并使用不同的参数(不同的数组类型),然后每个函数将处理其自己的数组。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接