C++:获取传递给函数的多维数组的行大小
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6934776/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++: getting the row size of a multidimensional array passed to a function
提问by Karl Giesing
I'm trying to write a function that will print out the contents of a multidimensional array. I know the size of the columns, but not the size of the rows.
我正在尝试编写一个函数来打印多维数组的内容。我知道列的大小,但不知道行的大小。
EDIT: Since I didn't make this clear, the arrays passed to this function are NOT dynamically allocated. The sizes are known at compile time.
编辑:由于我没有说清楚,传递给这个函数的数组不是动态分配的。大小在编译时是已知的。
I am testing it using a 3x2 array. Here is the function as it stands:
我正在使用 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];
}
}
}
Obviously, this only works if I know the size of "i" is 3 (it is in this case). Ideally, however, I would like the function to work no matter what the size of the first dimension.
显然,这仅在我知道“i”的大小为 3 时才有效(在这种情况下)。然而,理想情况下,无论第一维的大小如何,我都希望该函数能够工作。
I thought I would be able to do this using the sizeof() function, e.g.
我以为我可以使用 sizeof() 函数来做到这一点,例如
int size = sizeof(array1);
... and do some math from there.
...并从那里做一些数学运算。
Here's the odd part. If I use the sizeof() function inside the array, it returns a value of 4. I can use pointer notation to dereference the array:
这是奇怪的部分。如果我在数组中使用 sizeof() 函数,它将返回值 4。我可以使用指针表示法来取消引用数组:
int size = sizeof(*array1);
... but this actually returns a value of 8. This is odd, because the total size should be rows(which = 3) * columns(= 2) * sizeof(int)(= 4), or 24. And, indeed, this is the result, when I use sizeof(*array1) outsideof the function.
...但这实际上返回了 8 的值。这很奇怪,因为总大小应该是行(= 3)* 列(= 2)* sizeof(int)(= 4),或 24。而且,确实,这是我在函数外使用 sizeof(*array1) 时的结果。
Does anyone know what is going on here? More importantly, does anyone have a solution?
有谁知道这里发生了什么?更重要的是,有人有解决方案吗?
回答by Chris
The answer is that you can not do this. You must pass the number of rows as an argument to the function, or use an STL container such as std::vector
or std::array
.
答案是你不能这样做。您必须将行数作为参数传递给函数,或者使用 STL 容器,例如std::vector
或std::array
。
sizeof
is computed compile time; sizeof
is never useful in determining dynamic size of objects in C/C++. You (yourself, the programmer) can always calculate sizeof(x)
just from looking at code and header files since sizeof
counts the number of bytes used to represent the object. sizeof(*array1)
will always be 8 since array1[i]
is an array of two ints
and 4==sizeof(int)
. When you declare int array1[][2]
this is equivalent to int *array1[2]
. That is, array1
is a pointer to arrays of two integers. sizeof(array1)
is therefore 4 bytes, since it takes 4 bytes on your machine to represent a pointer.
sizeof
是计算编译时间;sizeof
在 C/C++ 中确定对象的动态大小从来没有用。你(你自己,程序员)总是sizeof(x)
可以通过查看代码和头文件来sizeof
计算,因为计算用于表示对象的字节数。sizeof(*array1)
将始终为 8,因为它array1[i]
是由两个ints
和组成的数组4==sizeof(int)
。当您声明int array1[][2]
this 等效于int *array1[2]
. 也就是说,array1
是一个指向两个整数数组的指针。sizeof(array1)
因此是 4 个字节,因为在您的机器上需要 4 个字节来表示一个指针。
回答by Conspicuous Compiler
You can accomplish this, to some degree, by using templated functions. The caveats are:
在某种程度上,您可以通过使用模板化函数来实现这一点。警告是:
- You will need to include the function definition (not just declaration) anywhere it is used
- It will only work when array size is fixed at compile time
- You will generate a separate function for every call to the function, resulting in some code bloat
- 您将需要在任何使用它的地方包含函数定义(不仅仅是声明)
- 它仅在编译时固定数组大小时才有效
- 您将为每次调用该函数生成一个单独的函数,从而导致一些代码膨胀
I am working form the code on this blog postby Kevin Heifner.
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];
}
}
}
回答by pmr
You can get the size of both arrays with some template magic:
您可以使用一些模板魔术来获取两个数组的大小:
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);
}
This only works for arrays whose bounds are known at compile time and not for dynamically allocated arrays.
这仅适用于其边界在编译时已知的数组,而不适用于动态分配的数组。
In any case: You should use std::vector
or boost::multiarray
.
在任何情况下:您应该使用std::vector
或boost::multiarray
。
回答by Seth Carnegie
The size is 8 outside the function because you're dereferencing the first array, which gives you the column size (2) times the size of an int
(4). If you wanted 24, you'd do sizeof(array)
(outside the function). The answer is 4 insidethe function because it treats array
like a pointer, the size of which is 4 bytes.
函数外的大小为 8,因为您正在取消引用第一个数组,这使您的列大小 (2) 乘以int
(4)的大小。如果你想要 24,你会做sizeof(array)
(在函数之外)。函数内部的答案是 4 ,因为它被视为array
一个指针,其大小为 4 个字节。
However, to reliably get the size of arrays that have been passed to functions, you either have to pass the size or use something like vector
.
但是,要可靠地获取已传递给函数的数组的大小,您必须传递大小或使用类似vector
.
回答by Captain Fantastic
A very simple way to do it, without needing vectors, templates, classes, or passing the size of the array, is to have a last row of data that contains something unique such as the following example, where a -1 is used in the last row, first column:
一个非常简单的方法,不需要向量、模板、类或传递数组的大小,是让最后一行数据包含一些独特的东西,例如以下示例,其中 -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);
Then just break out of the loop(s) when you reach that unique value:
然后,当您达到该唯一值时,就跳出循环:
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];
}
}
}
回答by Ken Wayne VanderLinde
Simply use better arrays!
只需使用更好的数组!
What I mean by that is you can make your own array class which wraps an array, or use some common libraries with such classes (e.g. boost). This is much more reliable, and likely is easier to reason about that straight-up C++ arrays.
我的意思是你可以创建自己的数组类来包装一个数组,或者使用一些带有此类类的公共库(例如 boost)。这更可靠,并且可能更容易推断出直接的 C++ 数组。
One reason for this is if your write the function
原因之一是如果您编写函数
void foo( int a[][2] )
{
// etc.
}
you don't actually have as many guarantees on the array as you might think. For example, it is notguaranteed that the second dimension of the array is two elements wide (I could be wrong about this point, as I don't have references on hand, but I'm pretty confident about it). This is because that actual signature for the function is
实际上,您对数组的保证并不像您想象的那么多。例如,不能保证数组的第二维是两个元素宽(我可能在这一点上是错的,因为我手头没有引用,但我对此非常有信心)。这是因为函数的实际签名是
void foo( int ** );
This is because arrays degenerate to pointers when used in function declarations (which is why you're sizeof(array)
returns 4, since 4 bytes is the size of a pointer type on your machine). Also, you clearlyhave no guarantee on the size of the first dimension, so assuming it is going to be 3 is dangerous, and potentially the result of confusing bugs in the future.
这是因为在函数声明中使用数组时会退化为指针(这就是sizeof(array)
返回 4 的原因,因为 4 个字节是您机器上指针类型的大小)。此外,您显然无法保证第一个维度的大小,因此假设它将是 3 是危险的,并且可能是将来混淆错误的结果。
This is where a custom array
class would be great, especially if it were templated. For example, a two dimensional array class could be declared like
这是自定义array
类会很棒的地方,特别是如果它是模板化的。例如,一个二维数组类可以声明为
template<typename T, int length1, int length2>
class Array2D
{
// Array2D's gutsy stuff to make it act kind of like T[length1][length2]
};
Using such an approach allows you to maintain allthe information about the array in anysituation, e.g.
使用这种方法可以让您在任何情况下维护有关数组的所有信息,例如
void foo( Array2D<int, 3, 2> &array ) {}
Now you can decide the sizes every dimension in the array.
现在您可以决定数组中每个维度的大小。
An added benefit, is that you can add bounds checking to your Array2D
class, which C++ array do not have. E.g. in a 3x2 array, you are able to access the fourth element in the first row, even though it's not conceptually valid. Such a common source of bugs can easily be eradicated by using an array class like Array2D.
一个额外的好处是,您可以向Array2D
类添加边界检查,而 C++ 数组则没有。例如,在 3x2 数组中,您可以访问第一行中的第四个元素,即使它在概念上无效。通过使用像 Array2D 这样的数组类,可以轻松地消除这种常见的错误来源。
There are some drawbacks, which is normal when using templates. The big one is that, because of the way template are instantiated, you have to define any templated classes in your header files, not in separate source files (technically, you can use the "export" keyword to do split the class up as normal, but this has limited support on major compilers).
有一些缺点,这在使用模板时很正常。最大的问题是,由于模板的实例化方式,您必须在头文件中定义任何模板化类,而不是在单独的源文件中(从技术上讲,您可以使用“export”关键字来正常拆分类,但这对主要编译器的支持有限)。
As a last note (if you're interested, as I am), the situation becomes even better in C++0x (comming soon!) with the advent of variadic templates:
最后一点(如果你有兴趣,就像我一样),随着可变参数模板的出现,C++0x 中的情况变得更好(即将推出!):
template<typenameT, int... lengths>
class Array
{
// etc...
};
Now all array types can be defined by a single class template. Never been easier.
现在所有数组类型都可以由单个类模板定义。从未如此简单。