Passing a 2D array to a C++ function
我有一个函数,作为参数,我想取一个可变大小的二维数组。
到目前为止,我有:
1 2 3 4 | void myFunction(double** myArray){ myArray[x][y] = 5; etc... } |
我在代码的其他地方声明了一个数组:
1 | double anArray[10][10]; |
但是,打电话给
我不想在传入数组时复制它。对
有三种方法可以将二维数组传递给函数:
参数是二维数组
1 2 3 4 5 6 | int array[10][10]; void passFunc(int a[][10]) { // ... } passFunc(array); |
参数是包含指针的数组
1 2 3 4 5 6 7 8 | 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); |
参数是指向指针的指针
1 2 3 4 5 6 7 8 9 | int **array; array = new int *[10]; for(int i = 0; i <10; i++) array[i] = new int[10]; void passFunc(int **a) { // ... } passFunc(array); |
固定尺寸
1。通过引用
1 2 3 4 5 6 7 8 9 10 11 12 | 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; } } |
在C++中,通过引用传递数组而不丢失维度信息可能是最安全的,因为不必担心调用方传递不正确的维度(编译器不匹配时的标志)。但是,对于动态(FreeStore)数组,这是不可能的;它只适用于自动(通常是堆栈活动)数组,也就是说,在编译时应该知道维数。
2。传递指针
1 2 3 4 5 6 7 8 9 10 11 | 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; } } |
前一个方法的C等价物正在通过指针传递数组。这不应该与传递数组的衰减指针类型(3)混淆,后者是常见的、流行的方法,尽管不如此方法安全,但更灵活。与(1)类似,当数组的所有维度都是固定的并且在编译时已知时,使用此方法。注意,在调用函数时,数组的地址应该通过
这些是从C继承的,但安全性较低,编译器无法进行检查,从而确保调用者正在传递所需的维度。该函数只存储调用者作为维度传入的内容。因为不同长度的数组总是可以传递给它们,所以它们比上述的数组更灵活。
要记住的是,没有这样的事情:将数组直接传递给C中的函数[而C++中它们可以作为引用传递(1)];(2)传递指向数组的指针,而不是数组本身。始终按原样传递数组将变为指针复制操作,这得益于数组衰减为指针的性质。
三。传递(值)指向衰减类型的指针
1 2 3 4 5 6 7 8 9 10 11 12 | // 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; } } |
虽然允许使用
4。将指针传递给指针
1 2 3 4 5 6 7 8 9 10 11 12 | // 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; } } |
还有一个可选的
注:(4)是最安全的选择,因为它几乎没有任何类型的检查和最不方便。不能合法地将一个二维数组传递给这个函数;C-FAQ谴责了执行
下面是一个用于测试上述功能的驱动程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #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** } |
对Shengy的第一个建议进行修改后,可以使用模板使函数接受多维数组变量(而不是存储必须管理和删除的指针数组):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | template <size_t size_x, size_t size_y> void func(double (&arr)[size_x][size_y]) { printf("%p ", &arr); } int main() { double a1[10][10]; double a2[5][5]; printf("%p %p ", &a1, &a2); func(a1); func(a2); return 0; } |
print语句显示数组是通过引用传递的(通过显示变量的地址)。
您可以创建这样的函数模板:
1 2 3 4 5 6 | template<int R, int C> void myFunction(double (&myArray)[R][C]) { myArray[x][y] = 5; etc... } |
然后,通过R和C可以同时获得两个维度大小。将为每个数组大小创建不同的函数,因此如果函数很大,并且使用各种不同的数组大小来调用它,那么这可能会很昂贵。但是,您可以将它用作类似以下函数的包装器:
1 2 3 4 5 | void myFunction(double * arr, int R, int C) { arr[x * C + y] = 5; etc... } |
它将数组视为一维数组,并使用算术计算出索引的偏移量。在这种情况下,您可以这样定义模板:
1 2 3 4 5 | template<int C, int R> void myFunction(double (&myArray)[R][C]) { myFunction(*myArray, R, C); } |
令人惊讶的是,还没有人提到这一点,但是您可以简单地在任何支持[][]语义的2d上创建模板。
1 2 3 4 5 6 7 8 9 | template <typename TwoD> void myFunction(TwoD& myArray){ myArray[x][y] = 5; etc... } // call with double anArray[10][10]; myFunction(anArray); |
它可以与任何二维"类似数组"的数据结构(如
1 2 | void f(double p[][10]) { } |
但是,这不会让您传递最后一个维度不是10的数组。
C++中最好的解决方案是使用EDCOX1〔1〕:它几乎是高效的,而且更方便。
你可以这样做…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #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... "; for(int i=0;i<rows;i++){ for(int j=0;j<cols;j++){ cout<<*(a+ i*rows + j)<<" "; } cout<<" "; } } 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; } |
你的输出如下…
1 2 | 11.5 12.5 13.5 14.5 |
一维数组衰减为指向数组中第一个元素的指针指针。当二维数组衰减到指向第一行的指针时。所以,函数原型应该是-
1 | void myFunction(double (*myArray) [10]); |
我更喜欢
这是向量矩阵的向量示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #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; } |
输出:
1 2 3 4 5 6 7 | 1 2 3 4 5 6 7 8 9 1 2 3 0 0 0 0 0 0 0 0 0 0 0 0 |
我们可以使用多种方法将二维数组传递给函数:
使用单指针,我们必须对二维数组进行类型转换。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#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;
}通过这种方式使用双指针,我们还可以对二维数组进行类型转换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #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(" "); } } 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; } |
传递多维数组的一个重要问题是:
- 无需指定
First array dimension 。 - 必须指定
Second(any any further)dimension 。
1.当只有第二个维度全局可用时(宏或全局常量)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | `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.使用单指针:在这个方法中,我们必须在传递给函数时对二维数组进行类型转换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | `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; }` |
你可以在C++中使用模板工具来完成这个任务。我做了这样的事:
1 2 3 4 | template<typename T, size_t col> T process(T a[][col], size_t row) { ... } |
这种方法的问题在于,对于您提供的每一个col值,都会使用模板实例化一个新的函数定义。所以,
1 2 3 | int some_mat[3][3], another_mat[4,5]; process(some_mat, 3); process(another_mat, 4); |
将模板实例化两次以生成两个函数定义(一个定义col=3,另一个定义col=5)。