将多维数组传递给参数类型为double *的函数

时间:2011-12-03 21:53:26

标签: c++ multidimensional-array

我使用的库将一个指向double数组的指针作为参数,如下所示:

const int N=10;
const int J=20;
double my_array[N*J];
libFunc(my_array, N, J);

我更愿意在我的代码中使用多维数组,并且我发现我可以通过解除引用我的多维双数组来调用libFunc,如下所示

double my_array2[N][J];
libFunc(&my_array2[0][0], N, J);

但是,我担心这段代码可能无法移植,因为N和M变大,它可能无法继续工作,并且可能存在其他隐藏的问题。

为什么这很糟糕,我应该在这里注意什么?使用多维数组并将它们传递给libFunc的正确方法是什么,就像它们是普通的双数组一样?

修改:阅读所选答案下方的评论,以便对手头的问题进行讨论。似乎如果我声明一个静态数组,如上所述,那么这个代码应该适用于大多数编译器。但是,如果数组是动态分配的,则可能存在问题。

3 个答案:

答案 0 :(得分:2)

没有简单的方法来制作副本。访问一个超出其边界的数组是未定义的行为,你不会解决这个问题。

现在,在许多情况下,您的代码可以正常工作,因为T[M * N]T[M][N]的内存以相同的方式布局。只要调用者和被调用者同时对编译器不可见,我就会猜测这应该有用。

但想象一下这种情况:

T a[M][N];

for (size_t i = 0; i != M * N; ++i)
{
  a[0][i] = 0;
}

这里编译器可能会推断a[0][N]超出范围,因此存在未定义的行为,编译器可能合法地省略整个循环,或者使应用程序崩溃或擦除硬盘。

所以......接受你的选择。未定义的行为在某个地方,但你可能会很幸运。

答案 1 :(得分:1)

C ++使用row-major ordering,因此您的多维数组实际上是内存中连续的1维区域。
即使声明为例如2维,它也可以通过index = x + y * height访问,因此不存在可移植性问题......

C++ documentation告诉:

  

多维数组只是程序员的抽象,因为   我们可以通过放置一个简单的数组来获得相同的结果   其指数之间的因素

(这里也是visual c++)的解释

答案 2 :(得分:1)

你基本上搞砸了:这个函数需要一个double *,所以你应该给它一个double *

最简单,最安全的方法是使用包装器。类似的东西:

template<size_t M, size_t N>
class Double2DArray
{
   std::vector<double> m_container ; // It could be a double[M * N]
                                     // But it could explode your stack
                                     // So let's use the heap
   public :
      // Etc.

      Double2DArray()
         : m_container(M * N)
      {
         // I assume the default you want is a vector already
         // filled with 0.0
      }

      size_t getSizeM() { return M ; }
      size_t getSizeN() { return N ; }

      double & operator() (size_t p_m, size_t p_n)
      {
         return m_container[p_m * N + p_n] ;
      }

      double * data()
      {
         return &(m_container[0]) ;
      }

      // etc.
} ;

当然,这段代码并不完整:至少,你应该添加访问器的const版本,可能会处理复制构造和赋值等。我不知道你的确切需求,所以,你的里程可能会有所不同,但核心理念是......

你可以使用这个包装器:

void foo()
{
   Double2DArray<42, 13> my2DArray ;

   // etc.

   my2DArray(3, 5) = 3.1415 ;     // set some value
   double d = my2DArray(13, 2)  ; // get some value

   // etc.

   libFunc(my2DArray.data(), my2DArray.getSizeM(), my2DArray.getSizeN());
}

我甚至会将libFunc重载为更安全:

template<size_t M, size_t N>
inline void libFunc(Double2DArray<M, N> & p_my2DArray)
{
   libFunc(p_my2DArray.data(), M, N);
}

这样我就可以调用它而不需要再次给它一个数组的大小(它很容易混合M和N):

void foo()
{
   Double2DArray<42, 13> my2DArray ;

   // etc.

   libFunc(my2DArray);
}

这就是我如何使用多维数组并将其提供给类似C的API,期望连续的双精度数组。

P.S。:如果在编译时不知道M和N,你只需要删除模板,并制作构造函数的M和N参数,一切都可以(差不多)相同。