我正在尝试编写一个打印出多维数组内容的函数。我知道列的大小,但不知道行的大小。
编辑:由于我没有说清楚,传递给这个函数的数组不是动态分配的。这些大小在编译时是已知的。
我正在使用3x2阵列进行测试。这是现在的功能:
void printArrays(int array1[][2], int array2[][2]) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
cout << "\narray1[" << i << "][" << j << "] = "
<< setfill('0') << setw(2) << array1[i][j]
<< "\tarray2[" << i << "][" << j << "] = "
<< setfill('0') << setw(2) << array2[i][j];
}
}
}
显然,这只有在我知道“i”的大小为3(在这种情况下)时才有效。然而,理想情况下,无论第一维的大小如何,我都希望该函数能够正常工作。
我以为我可以使用sizeof()函数来做到这一点,例如
int size = sizeof(array1);
......然后从那里做一些数学。
这是奇怪的部分。如果我在数组中使用sizeof()函数,它返回值4.我可以使用指针表示法取消引用数组:
int size = sizeof(*array1);
...但这实际上返回值8.这很奇怪,因为总大小应该是行(= 3)*列(= 2)* sizeof(int)(= 4)或24。事实上,当我在函数外使用sizeof(* array1) 时,这就是结果。
有谁知道这里发生了什么?更重要的是,有没有人有解决方案?
答案 0 :(得分:8)
答案是你不能这样做。您必须将行数作为参数传递给函数,或使用STL容器,例如std::vector
或std::array
。
sizeof
是计算编译时间; sizeof
在确定C / C ++中对象的动态大小时永远不会有用。你(你自己,程序员)总是可以通过查看代码和头文件来计算sizeof(x)
,因为sizeof
计算用于表示对象的字节数。 sizeof(*array1)
始终为8,因为array1[i]
是两个ints
和4==sizeof(int)
的数组。当您声明int array1[][2]
时,这相当于int *array1[2]
。也就是说,array1
是指向两个整数数组的指针。因此,sizeof(array1)
是4个字节,因为在您的机器上需要4个字节来表示指针。
答案 1 :(得分:4)
您可以通过使用模板化函数在某种程度上完成此操作。警告是:
我是Kevin Heifner的working form the code on this blog post。
template <typename T>
struct array_info
{
};
template <typename T, size_t N, size_t M>
struct array_info<T[N][M]>
{
typedef T type;
enum { size1 = N, size2 = M };
};
template <typename A1>
void printArrays(A1 array1, A1 array2) {
size_t A1_i = array_info<A1>::size1;
size_t A1_j = array_info<A1>::size2;
for (size_t i = 0; i < A1_i; i++) {
for (size_t j = 0; j < A1_j; j++) {
cout << "\narray1[" << i << "][" << j << "] = "
<< setfill('0') << setw(2) << array1[i][j]
<< "\tarray2[" << i << "][" << j << "] = "
<< setfill('0') << setw(2) << array2[i][j];
}
}
}
答案 2 :(得分:3)
你可以通过一些模板魔法获得两个数组的大小:
template< typename T, std::size_t n, std::size_t m >
void foo( T(&)[n][m] ) {
std::cout << n << " " << m << std::endl;
}
int main() {
int a[3][3];
int b[2][5];
foo(a); foo(b);
}
这仅适用于在编译时已知边界的数组,而不适用于动态分配的数组。
无论如何:您应该使用std::vector
或boost::multiarray
。
答案 3 :(得分:2)
函数外部的大小为8,因为您取消引用了第一个数组,这使您的列大小(2)倍于int
(4)的大小。如果你想要24,你可以sizeof(array)
(在函数之外)。答案是4 inside 函数,因为它将array
视为一个指针,其大小为4个字节。
但是,要可靠地获取已传递给函数的数组的大小,您必须传递大小或使用类似vector
的内容。
答案 4 :(得分:1)
一个非常简单的方法,不需要向量,模板,类或传递数组的大小,就是让最后一行数据包含一些独特的东西,例如下面的例子,其中-1是用在最后一行,第一列:
#define DATA_WIDTH 7
const float block10g[][DATA_WIDTH] = {
{0, 15, 25, 50, 75, 100, 125},
{2.12, 0, 1.000269, 3.000807, 4.24114056, 5.28142032, 6.001614},
{6.36, 0, 1.2003228, 3.84103296, 6.24167856, 8.16219504, 10.08271152},
{10.6, 0, 1.2003228, 4.4011836, 7.2019368, 9.2024748, 11.8031742},
{21.2, 0, 2.000538, 6.001614, 8.002152, 10.4027976, 14.4038736},
{ -1}
};
const float block10g[][DATA_WIDTH] = {
{0, 20, 50, 100, 150, 200, 250},
{2.12, 0, 2.88077472, 5.04135576, 5.84157096, 6.08163552, 5.84157096},
{6.36, 0, 3.84103296, 7.92213048, 11.52309888, 13.56364764, 14.4038736},
{10.6, 0, 3.8010222, 8.8023672, 13.003497, 16.4044116, 18.4049496},
{21.2, 0, 4.4011836, 9.2024748, 14.003766, 18.4049496, 22.4060256},
{ -1}
};
printArrays(block10g,block20g);
然后在达到唯一值时突然退出循环:
void printArrays(float array1[][DATA_WIDTH], float array2[][DATA_WIDTH]) {
for (int i = 0; array1[i][0]!=-1 && array2[i][0]!=-1 ; i++) {
for (int j = 0; j < DATA_WIDTH; j++) {
cout << "\narray1[" << i << "][" << j << "] = "
<< array1[i][j]
<< "\tarray2[" << i << "][" << j << "] = "
<< array2[i][j];
}
}
}
答案 5 :(得分:0)
只需使用更好的阵列!
我的意思是你可以创建自己的包装数组的数组类,或者使用一些带有这些类的公共库(例如boost)。这样更可靠,并且可能更容易推理出直接的C ++数组。
这样做的一个原因是你写了函数
void foo( int a[][2] )
{
// etc.
}
你实际上并没有像你想象的那样在数组上有多少保证。例如,不保证数组的第二个维度是两个元素的宽度(关于这一点我可能是错的,因为我手边没有参考,但我非常自信关于它)。这是因为该函数的实际签名是
void foo( int ** );
这是因为当在函数声明中使用时,数组会退化为指针(这就是为什么你sizeof(array)
返回4,因为4个字节是你机器上指针类型的大小)。此外,您显然无法保证第一维的大小,因此假设它将是3是危险的,并且可能是将来混淆错误的结果。
这是自定义array
类很棒的地方,特别是如果它是模板化的。例如,二维数组类可以声明为
template<typename T, int length1, int length2>
class Array2D
{
// Array2D's gutsy stuff to make it act kind of like T[length1][length2]
};
使用这种方法可以在任何情况下维护所有有关数组的信息,例如
void foo( Array2D<int, 3, 2> &array ) {}
现在您可以决定数组中每个维度的大小。
另一个好处是,您可以将边界检查添加到Array2D
类,而C ++数组没有。例如。在3x2数组中,您可以访问第一行中的第四个元素,即使它在概念上没有效果。通过使用像Array2D这样的数组类,可以很容易地消除这种常见的错误源。
有一些缺点,使用模板时很正常。最重要的是,由于模板的实例化方式,你必须在头文件中定义任何模板化的类,而不是在单独的源文件中定义(从技术上讲,你可以使用“export”关键字将类拆分为正常,但这对主要编译器的支持有限。)
作为最后一点(如果你感兴趣,就像我一样),随着可变参数模板的出现,C ++ 0x(即将推出!)的情况会变得更好:
template<typenameT, int... lengths>
class Array
{
// etc...
};
现在所有数组类型都可以由单个类模板定义。从未如此简单。