本文翻译自:Passing a 2D array to a C++ function
I have a function which I want to take, as a parameter, a 2D array of variable size. 我有一个函数,希望将可变大小的2D数组作为参数。
So far I have this: 到目前为止,我有这个:
void myFunction(double** myArray){
myArray[x][y] = 5;
etc...
}
And I have declared an array elsewhere in my code: 我在代码的其他地方声明了一个数组:
double anArray[10][10];
However, calling myFunction(anArray)
gives me an error. 但是,调用myFunction(anArray)
给我一个错误。
I do not want to copy the array when I pass it in. Any changes made in myFunction
should alter the state of anArray
. 我不想在传递数组时复制它myFunction
所做的任何更改都应更改anArray
的状态。 If I understand correctly, I only want to pass in as an argument a pointer to a 2D array. 如果我理解正确,我只想将指向2D数组的指针作为参数传递。 The function needs to accept arrays of different sizes also. 该函数还需要接受不同大小的数组。 So for example, [10][10]
and [5][5]
. 因此,例如[10][10]
和[5][5]
。 How can I do this? 我怎样才能做到这一点?
#1楼
参考:https://stackoom.com/question/amju/将-D数组传递给C-函数
#2楼
Fixed Size 固定尺寸
1. Pass by reference 1.通过引用传递
template <size_t rows, size_t cols>
void process_2d_array_template(int (&array)[rows][cols])
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < cols; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
In C++ passing the array by reference without losing the dimension information is probably the safest, since one needn't worry about the caller passing an incorrect dimension (compiler flags when mismatching). 在C ++中,通过引用传递数组而不丢失维度信息可能是最安全的,因为不必担心调用者传递的维度错误(不匹配时的编译器标志)。 However, this isn't possible with dynamic (freestore) arrays; 但是,这对于动态(免费存储)数组是不可能的。 it works for automatic ( usually stack-living ) arrays only ie the dimensionality should be known at compile time. 它仅适用于自动( 通常为栈式 )数组,即应在编译时知道维数。
2. Pass by pointer 2.通过指针传递
void process_2d_array_pointer(int (*array)[5][10])
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < 5; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < 10; ++j)
std::cout << (*array)[i][j] << '\t';
std::cout << std::endl;
}
}
The C equivalent of the previous method is passing the array by pointer. 与先前方法等效的C语言是通过指针传递数组。 This should not be confused with passing by the array's decayed pointer type (3) , which is the common, popular method, albeit less safe than this one but more flexible. 这不应与传递数组的衰变指针类型(3)混淆,后者是一种常见的流行方法,尽管比此方法安全性较低,但更灵活。 Like (1) , use this method when all the dimensions of the array is fixed and known at compile-time. 与(1)一样,当数组的所有维度都是固定的并且在编译时已知时,请使用此方法。 Note that when calling the function the array's address should be passed process_2d_array_pointer(&a)
and not the address of the first element by decay process_2d_array_pointer(a)
. 请注意,调用当阵列的地址应该传递函数process_2d_array_pointer(&a)
通过衰减,而不是第一个元素的地址process_2d_array_pointer(a)
。
Variable Size 可变大小
These are inherited from C but are less safe, the compiler has no way of checking, guaranteeing that the caller is passing the required dimensions. 它们是从C继承的,但是安全性较低,编译器无法进行检查,从而保证了调用者正在传递所需的尺寸。 The function only banks on what the caller passes in as the dimension(s). 该函数仅基于调用者传递的维度作为维度。 These are more flexible than the above ones since arrays of different lengths can be passed to them invariably. 由于可以将不同长度的数组不变地传递给它们,因此它们比上面的更具灵活性。
It is to be remembered that there's no such thing as passing an array directly to a function in C [while in C++ they can be passed as a reference (1) ]; 要记住的是,没有这样的事情:将数组直接传递给C中的函数[而在C ++中,它们可以作为引用传递(1) ]; (2) is passing a pointer to the array and not the array itself. (2)将指针传递给数组,而不是数组本身。 Always passing an array as-is becomes a pointer-copy operation which is facilitated by array's nature of decaying into a pointer . 始终按原样传递数组会成为指针复制操作,这会因数组衰减为指针的性质而变得容易 。
3. Pass by (value) a pointer to the decayed type 3.通过(值)指向衰减类型的指针
// int array[][10] is just fancy notation for the same thing
void process_2d_array(int (*array)[10], size_t rows)
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < 10; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
Although int array[][10]
is allowed, I'd not recommend it over the above syntax since the above syntax makes it clear that the identifier array
is a single pointer to an array of 10 integers, while this syntax looks like it's a 2D array but is the same pointer to an array of 10 integers. 尽管允许使用int array[][10]
,但我不建议在上述语法中使用它,因为上述语法清楚地表明标识符array
是指向10个整数的数组的单个指针,而该语法看起来像是一个2D数组,但指向10个整数的数组相同。 Here we know the number of elements in a single row (ie the column size, 10 here) but the number of rows is unknown and hence to be passed as an argument. 在这里,我们知道单行中的元素数(即列大小,此处为10),但是行数是未知的,因此将作为参数传递。 In this case there's some safety since the compiler can flag when a pointer to an array with second dimension not equal to 10 is passed. 在这种情况下,由于编译器可以在传递第二维不等于10的数组的指针时进行标记,因此具有一定的安全性。 The first dimension is the varying part and can be omitted. 第一维是变化的部分,可以省略。 See here for the rationale on why only the first dimension is allowed to be omitted. 有关为什么只允许省略第一维的基本原理 , 请参见此处 。
4. Pass by pointer to a pointer 4.通过指针传递到指针
// int *array[10] is just fancy notation for the same thing
void process_pointer_2_pointer(int **array, size_t rows, size_t cols)
{
std::cout << __func__ << std::endl;
for (size_t i = 0; i < rows; ++i)
{
std::cout << i << ": ";
for (size_t j = 0; j < cols; ++j)
std::cout << array[i][j] << '\t';
std::cout << std::endl;
}
}
Again there's an alternative syntax of int *array[10]
which is the same as int **array
. 再次有int *array[10]
的另一种语法,它与int **array
相同。 In this syntax the [10]
is ignored as it decays into a pointer thereby becoming int **array
. 在这种语法中, [10]
会衰减为指针,从而变成int **array
因此将被忽略。 Perhaps it is just a cue to the caller that the passed array should have at least 10 columns, even then row count is required. 也许这只是调用者的提示,即使需要行计数,传递的数组也应至少具有10列。 In any case the compiler doesn't flag for any length/size violations (it only checks if the type passed is a pointer to pointer), hence requiring both row and column counts as parameter makes sense here. 在任何情况下,编译器都不会标记任何长度/大小违规(它只会检查传递的类型是否是指向指针的指针),因此在这里需要将行数和列数都作为参数。
Note: (4) is the least safest option since it hardly has any type check and the most inconvenient. 注意: (4)是最不安全的选项,因为它几乎没有任何类型检查且最不方便。 One cannot legitimately pass a 2D array to this function; 人们不能合法地将2D数组传递给此函数; C-FAQ condemns the usual workaround of doing int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);
C-FAQ谴责执行int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);
的通常方法int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);
int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);
as it may potentially lead to undefined behaviour due to array flattening. 因为它可能由于数组展平而导致不确定的行为 。 The right way of passing an array in this method brings us to the inconvenient part ie we need an additional (surrogate) array of pointers with each of its element pointing to the respective row of the actual, to-be-passed array; 用这种方法传递数组的正确方法将我们带到了不便之处,即我们需要一个额外的(替代)指针数组,其每个元素都指向实际的要传递的数组的相应行; this surrogate is then passed to the function (see below); 然后将此代理传递给函数(请参见下文); all this for getting the same job done as the above methods which are more safer, cleaner and perhaps faster. 所有这些都是为了完成与上述方法更安全,更清洁甚至更快的工作。
Here's a driver program to test the above functions: 这是一个测试上述功能的驱动程序:
#include <iostream>
// copy above functions here
int main()
{
int a[5][10] = { { } };
process_2d_array_template(a);
process_2d_array_pointer(&a); // <-- notice the unusual usage of addressof (&) operator on an array
process_2d_array(a, 5);
// works since a's first dimension decays into a pointer thereby becoming int (*)[10]
int *b[5]; // surrogate
for (size_t i = 0; i < 5; ++i)
{
b[i] = a[i];
}
// another popular way to define b: here the 2D arrays dims may be non-const, runtime var
// int **b = new int*[5];
// for (size_t i = 0; i < 5; ++i) b[i] = new int[10];
process_pointer_2_pointer(b, 5, 10);
// process_2d_array(b, 5);
// doesn't work since b's first dimension decays into a pointer thereby becoming int**
}
#3楼
You can do something like this... 你可以做这样的事情...
#include<iostream>
using namespace std;
//for changing values in 2D array
void myFunc(double *a,int rows,int cols){
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
*(a+ i*rows + j)+=10.0;
}
}
}
//for printing 2D array,similar to myFunc
void printArray(double *a,int rows,int cols){
cout<<"Printing your array...\n";
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
cout<<*(a+ i*rows + j)<<" ";
}
cout<<"\n";
}
}
int main(){
//declare and initialize your array
double a[2][2]={{1.5 , 2.5},{3.5 , 4.5}};
//the 1st argument is the address of the first row i.e
//the first 1D array
//the 2nd argument is the no of rows of your array
//the 3rd argument is the no of columns of your array
myFunc(a[0],2,2);
//same way as myFunc
printArray(a[0],2,2);
return 0;
}
Your output will be as follows... 您的输出将如下所示...
11.5 12.5
13.5 14.5
#4楼
Surprised that no one mentioned this yet, but you can simply template on anything 2D supporting [][] semantics. 令人惊讶的是没有人提到这一点,但是您可以简单地在任何支持[] []语义的2D模板上。
template <typename TwoD>
void myFunction(TwoD& myArray){
myArray[x][y] = 5;
etc...
}
// call with
double anArray[10][10];
myFunction(anArray);
It works with any 2D "array-like" datastructure, such as std::vector<std::vector<T>>
, or a user defined type to maximize code reuse. 它可以与任何2D“类似数组”的数据结构一起使用,例如std::vector<std::vector<T>>
或用户定义的类型,以最大程度地提高代码重用性。
#5楼
You can use template facility in C++ to do this. 您可以使用C ++中的模板工具来执行此操作。 I did something like this : 我做了这样的事情:
template<typename T, size_t col>
T process(T a[][col], size_t row) {
...
}
the problem with this approach is that for every value of col which you provide, the a new function definition is instantiated using the template. 这种方法的问题在于,对于您提供的col的每个值,都会使用模板实例化一个新的函数定义。 so, 所以,
int some_mat[3][3], another_mat[4,5];
process(some_mat, 3);
process(another_mat, 4);
instantiates the template twice to produce 2 function definitions (one where col = 3 and one where col = 5). 实例化模板两次以产生2个函数定义(其中col = 3的一个和col = 5的一个)。
#6楼
One important thing for passing multidimensional arrays is: 传递多维数组的重要一件事是:
-
First array dimension
need not be specified. 无需指定First array dimension
。 -
Second(any any further)dimension
must be specified. 必须指定Second(any any further)dimension
。
1.When only second dimension is available globally (either as a macro or as a global constant) 1,全局只有第二维可用时(作为宏或全局常数)
`const int N = 3;
`void print(int arr[][N], int m)
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < N; j++)
printf("%d ", arr[i][j]);
}`
int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
print(arr, 3);
return 0;
}`
2.Using a single pointer : In this method,we must typecast the 2D array when passing to function. 2.使用单个指针 :在此方法中,传递给函数时必须对2D数组进行类型转换。
`void print(int *arr, int m, int n)
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
printf("%d ", *((arr+i*n) + j));
}
`int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int m = 3, n = 3;
// We can also use "print(&arr[0][0], m, n);"
print((int *)arr, m, n);
return 0;
}`