将二维数组传递给 C++ 函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8767166/
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
Passing a 2D array to a C++ function
提问by RogerDarwin
I have a function which I want to take, as a parameter, a 2D array of variable size.
我有一个函数,我想将它作为参数,一个可变大小的二维数组。
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
. If I understand correctly, I only want to pass in as an argument a pointer to a 2D array. The function needs to accept arrays of different sizes also. So for example, [10][10]
and [5][5]
. How can I do this?
我不想在传入数组时复制它。 中所做的任何更改都myFunction
应该改变anArray
. 如果我理解正确,我只想将指向二维数组的指针作为参数传入。该函数还需要接受不同大小的数组。例如,[10][10]
和[5][5]
。我怎样才能做到这一点?
回答by shengy
There are three ways to pass a 2D array to a function:
将二维数组传递给函数的方法有以下三种:
The parameter is a 2D array
int array[10][10]; void passFunc(int a[][10]) { // ... } passFunc(array);
The parameter is an array containing pointers
int *array[10]; for(int i = 0; i < 10; i++) array[i] = new int[10]; void passFunc(int *a[10]) //Array containing pointers { // ... } passFunc(array);
The parameter is a pointer to a pointer
int **array; array = new int *[10]; for(int i = 0; i <10; i++) array[i] = new int[10]; void passFunc(int **a) { // ... } passFunc(array);
参数是一个二维数组
int array[10][10]; void passFunc(int a[][10]) { // ... } passFunc(array);
参数是一个包含指针的数组
int *array[10]; for(int i = 0; i < 10; i++) array[i] = new int[10]; void passFunc(int *a[10]) //Array containing pointers { // ... } passFunc(array);
参数是一个指向指针的指针
int **array; array = new int *[10]; for(int i = 0; i <10; i++) array[i] = new int[10]; void passFunc(int **a) { // ... } passFunc(array);
回答by legends2k
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). However, this isn't possible with dynamic (freestore) arrays; it works for automatic (usually stack-living) arrays only i.e. the dimensionality should be known at compile time.
在 C++ 中,通过引用传递数组而不丢失维度信息可能是最安全的,因为人们不必担心调用者传递不正确的维度(不匹配时的编译器标志)。但是,这对于动态(freestore)数组是不可能的;它仅适用于自动(通常是堆栈式)数组,即在编译时应该知道维度。
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. 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. Like (1), use this method when all the dimensions of the array is fixed and known at compile-time. 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)
.
前一种方法的 C 等效项是通过指针传递数组。这不应该与传递数组的衰减指针类型(3)混淆,这是一种常见的流行方法,虽然不如这种方法安全但更灵活。像(1)一样,当数组的所有维度在编译时都是固定的并且已知时,请使用此方法。请注意,在调用该函数时,应该传递数组的地址,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. 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.
这些是从 C 继承的,但不太安全,编译器无法检查,保证调用者传递所需的维度。该函数仅依赖于调用者作为维度传入的内容。这些比上面的更灵活,因为可以始终将不同长度的数组传递给它们。
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)]; (2)is passing a pointer to the array and not the array itself. Always passing an array as-is becomes a pointer-copy operation which is facilitated by array's nature of decaying into a pointer.
需要记住的是,在 C 中没有将数组直接传递给函数这样的事情 [而在 C++ 中,它们可以作为引用传递(1)];(2)传递一个指向数组的指针而不是数组本身。始终按原样传递数组变成了指针复制操作,这得益于数组衰减为指针的性质。
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 lookslike it's a 2D array but is the same pointer to an array of 10 integers. Here we know the number of elements in a single row (i.e. the column size, 10 here) but the number of rows is unknown and hence to be passed as an argument. 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. The first dimension is the varying part and can be omitted. See here for the rationaleon why only the first dimension is allowed to be omitted.
虽然int array[][10]
是允许的,但我不建议使用上面的语法,因为上面的语法清楚地表明标识符array
是指向 10 个整数数组的单个指针,而此语法看起来像是一个二维数组,但与指向的指针相同一个由 10 个整数组成的数组。此处我们知道单行中的元素数(即列大小,此处为 10)但行数未知,因此将作为参数传递。在这种情况下,有一些安全性,因为编译器可以在传递指向第二维不等于 10 的数组的指针时进行标记。第一个维度是变化的部分,可以省略。有关为什么只允许省略第一个维度的基本原理,请参见此处。
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
. In this syntax the [10]
is ignored as it decays into a pointer thereby becoming 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. 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.
同样,还有一种int *array[10]
与int **array
. 在此语法中,[10]
被忽略,因为它衰减为指针从而变为int **array
。也许这只是对调用者的一个提示,即传递的数组应该至少有 10 列,即使需要行计数。在任何情况下,编译器都不会标记任何长度/大小违规(它只检查传递的类型是否是指向指针的指针),因此需要行和列计数作为参数在这里是有意义的。
Note:(4) is the least safest optionsince it hardly has any type check and the most inconvenient. One cannot legitimately pass a 2D array to this function; C-FAQ condemnsthe usual workaround of doing int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);
as it may potentially lead to undefined behaviourdue to array flattening. The right way of passing an array in this method brings us to the inconvenient part i.e. 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.
注意:(4) 是最不安全的选项,因为它几乎没有任何类型检查并且最不方便。不能合法地将二维数组传递给这个函数;C-FAQ 谴责通常的解决方法,int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);
因为它可能会由于数组扁平化而导致未定义的行为。在此方法中传递数组的正确方法将我们带到了不方便的部分,即我们需要一个额外的(代理)指针数组,其每个元素都指向实际的、要传递的数组的相应行;然后将此代理传递给函数(见下文);所有这些都是为了完成与上述方法相同的工作,这些方法更安全、更清洁,也许更快。
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**
}
回答by Zrax
A modification to shengy's first suggestion, you can use templates to make the function accept a multi-dimensional array variable (instead of storing an array of pointers that have to be managed and deleted):
修改shengy的第一个建议,您可以使用模板使函数接受多维数组变量(而不是存储必须管理和删除的指针数组):
template <size_t size_x, size_t size_y>
void func(double (&arr)[size_x][size_y])
{
printf("%p\n", &arr);
}
int main()
{
double a1[10][10];
double a2[5][5];
printf("%p\n%p\n\n", &a1, &a2);
func(a1);
func(a2);
return 0;
}
The print statements are there to show that the arrays are getting passed by reference (by displaying the variables' addresses)
打印语句是为了表明数组是通过引用传递的(通过显示变量的地址)
回答by LemonPi
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.
它适用于任何二维“类数组”数据结构,例如std::vector<std::vector<T>>
,或用户定义的类型,以最大限度地重用代码。
回答by Benjamin Lindley
You can create a function template like this:
您可以像这样创建一个函数模板:
template<int R, int C>
void myFunction(double (&myArray)[R][C])
{
myArray[x][y] = 5;
etc...
}
Then you have both dimension sizes via R and C. A different function will be created for each array size, so if your function is large and you call it with a variety of different array sizes, this may be costly. You could use it as a wrapper over a function like this though:
然后你通过 R 和 C 获得两个维度大小。将为每个数组大小创建一个不同的函数,所以如果你的函数很大并且你用各种不同的数组大小调用它,这可能会很昂贵。您可以将它用作这样的函数的包装器:
void myFunction(double * arr, int R, int C)
{
arr[x * C + y] = 5;
etc...
}
It treats the array as one dimensional, and uses arithmetic to figure out the offsets of the indexes. In this case, you would define the template like this:
它将数组视为一维数组,并使用算术计算出索引的偏移量。在这种情况下,您可以像这样定义模板:
template<int C, int R>
void myFunction(double (&myArray)[R][C])
{
myFunction(*myArray, R, C);
}
回答by dasblinkenlight
anArray[10][10]
is not a pointer to a pointer, it is a contiguous chunk of memory suitable for storing 100 values of type double, which compiler knows how to address because you specified the dimensions. You need to pass it to a function as an array. You can omit the size of the initial dimension, as follows:
anArray[10][10]
不是指向指针的指针,它是适合存储 100 个 double 类型值的连续内存块,编译器知道如何寻址,因为您指定了维度。您需要将它作为数组传递给函数。您可以省略初始尺寸的大小,如下所示:
void f(double p[][10]) {
}
However, this will not let you pass arrays with the last dimension other than ten.
但是,这不会让您传递最后一维不是十维的数组。
The best solution in C++ is to use std::vector<std::vector<double> >
: it is nearly as efficient, and significantly more convenient.
C++ 中的最佳解决方案是使用std::vector<std::vector<double> >
:它几乎同样有效,而且更加方便。
回答by Mahesh
Single dimensional array decays to a pointer pointer pointing to the first element in the array. While a 2D array decays to a pointer pointing to first row. So, the function prototype should be -
一维数组衰减为指向数组中第一个元素的指针指针。二维数组衰减为指向第一行的指针。所以,函数原型应该是——
void myFunction(double (*myArray) [10]);
I would prefer std::vector
over raw arrays.
我更喜欢std::vector
原始数组。
回答by Sagar Shah
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
回答by edW
Here is a vector of vectors matrix example
这是向量矩阵示例的向量
#include <iostream>
#include <vector>
using namespace std;
typedef vector< vector<int> > Matrix;
void print(Matrix& m)
{
int M=m.size();
int N=m[0].size();
for(int i=0; i<M; i++) {
for(int j=0; j<N; j++)
cout << m[i][j] << " ";
cout << endl;
}
cout << endl;
}
int main()
{
Matrix m = { {1,2,3,4},
{5,6,7,8},
{9,1,2,3} };
print(m);
//To initialize a 3 x 4 matrix with 0:
Matrix n( 3,vector<int>(4,0));
print(n);
return 0;
}
output:
输出:
1 2 3 4
5 6 7 8
9 1 2 3
0 0 0 0
0 0 0 0
0 0 0 0
回答by rashedcs
We can use several ways to pass a 2D array to a function:
我们可以使用多种方式将二维数组传递给函数:
Using single pointerwe have to typecast the 2D array.
#include<bits/stdc++.h> using namespace std; void func(int *arr, int m, int n) { for (int i=0; i<m; i++) { for (int j=0; j<n; j++) { cout<<*((arr+i*n) + j)<<" "; } cout<<endl; } } int main() { int m = 3, n = 3; int arr[m][n] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; func((int *)arr, m, n); return 0; }
Using double pointerIn this way, we also typecast the 2d array
使用单指针我们必须对二维数组进行类型转换。
#include<bits/stdc++.h> using namespace std; void func(int *arr, int m, int n) { for (int i=0; i<m; i++) { for (int j=0; j<n; j++) { cout<<*((arr+i*n) + j)<<" "; } cout<<endl; } } int main() { int m = 3, n = 3; int arr[m][n] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; func((int *)arr, m, n); return 0; }
使用双指针这样,我们也对二维数组进行了类型转换
#include<bits/stdc++.h>
using namespace std;
void func(int **arr, int row, int col)
{
for (int i=0; i<row; i++)
{
for(int j=0 ; j<col; j++)
{
cout<<arr[i][j]<<" ";
}
printf("\n");
}
}
int main()
{
int row, colum;
cin>>row>>colum;
int** arr = new int*[row];
for(int i=0; i<row; i++)
{
arr[i] = new int[colum];
}
for(int i=0; i<row; i++)
{
for(int j=0; j<colum; j++)
{
cin>>arr[i][j];
}
}
func(arr, row, colum);
return 0;
}