我使用的库将一个指向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
的正确方法是什么,就像它们是普通的双数组一样?
修改:阅读所选答案下方的评论,以便对手头的问题进行讨论。似乎如果我声明一个静态数组,如上所述,那么这个代码应该适用于大多数编译器。但是,如果数组是动态分配的,则可能存在问题。
答案 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
访问,因此不存在可移植性问题......
多维数组只是程序员的抽象,因为 我们可以通过放置一个简单的数组来获得相同的结果 其指数之间的因素
(这里也是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参数,一切都可以(差不多)相同。