我有一个我想要的功能,作为参数,一个可变大小的2D数组。
到目前为止,我有这个:
void myFunction(double** myArray){
myArray[x][y] = 5;
etc...
}
我在代码的其他地方声明了一个数组:
double anArray[10][10];
但是,调用myFunction(anArray)
会给我一个错误。
我在传入数组时不想复制数组。myFunction
中所做的任何更改都应该改变anArray
的状态。如果我理解正确,我只想作为参数传入指向2D数组的指针。该函数还需要接受不同大小的数组。例如,[10][10]
和[5][5]
。我怎么能这样做?
答案 0 :(得分:371)
将2D数组传递给函数有三种方法:
参数是2D数组
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);
答案 1 :(得分:150)
<强> 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;
}
}
在C ++中通过引用传递数组而不丢失维度信息可能是最安全的,因为不必担心调用者传递不正确的维度(编译器标记不匹配时)。但是,动态(freestore)数组不可能实现这一点;它仅适用于自动(usually stack-living)数组,即维度应在编译时知道。
<强> 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;
}
}
前一种方法的C等价物是通过指针传递数组。这不应该与通过数组的衰减指针类型(3)混淆,这是常见的,流行的方法,虽然不如这个安全但更灵活。与(1)一样,当数组的所有维度都已修复并在编译时已知时,请使用此方法。请注意,在调用函数时,数组的地址应该通过process_2d_array_pointer(&a)
传递process_2d_array_pointer(a)
而不是第一个元素的地址。
这些是从C继承但不太安全,编译器无法检查,保证调用者传递所需的维度。该函数仅保留调用者传入的维度。这些比上面的更灵活,因为不同长度的数组总是可以传递给它们。
需要记住的是,没有将数组直接传递给C中的函数[在C ++中它们可以作为参考传递(1)]; (2)传递指向数组的指针,而不是数组本身。始终按原样传递数组成为指针复制操作,由array's nature of decaying into a pointer促进。
第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;
}
}
虽然允许int array[][10]
,但我不建议使用上述语法,因为上面的语法清楚地表明标识符array
是指向10个整数数组的单个指针,而这个语法看起来就像它是一个2D数组,但它是指向10个整数数组的指针。这里我们知道单行中元素的数量(即列大小,这里是10),但行数是未知的,因此作为参数传递。在这种情况下,由于编译器可以标记何时传递指向第二维不等于10的数组的指针,因此存在一些安全性。第一个维度是变化的部分,可以省略。 See here for the rationale说明为什么只允许省略第一个维度。
<强> 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;
}
}
同样,int *array[10]
的替代语法与int **array
相同。在此语法中,[10]
将被忽略,因为它会衰减为指针,从而变为int **array
。也许这只是调用者的一个提示,传递的数组应该至少有10列,即使那时行数也是必需的。在任何情况下,编译器都不会标记任何长度/大小违规(它只检查传递的类型是否是指向指针的指针),因此需要行和列计数,因为参数在这里是有意义的。
注意: (4)是最安全的选项,因为它几乎没有任何类型检查且最不方便。人们无法合法地将2D数组传递给此函数; C-FAQ condemns由于数组展平而执行int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);
may potentially lead to undefined behaviour的常用解决方法。在这种方法中传递数组的正确方法将我们带到了不方便的部分,即我们需要一个额外的(代理)指针数组,其每个元素指向实际的待传递数组的相应行;然后将这个代理传递给函数(见下文);这一切都是为了完成与上述方法相同的工作,这些方法更安全,更清洁,也许更快。
这是一个测试上述功能的驱动程序:
#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**
}
答案 2 :(得分:38)
对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;
}
print语句用于显示数组是通过引用传递的(通过显示变量的地址)
答案 3 :(得分:20)
您可以像这样创建一个功能模板:
template<int R, int C>
void myFunction(double (&myArray)[R][C])
{
myArray[x][y] = 5;
etc...
}
然后通过R和C获得两个尺寸大小。将为每个数组大小创建不同的函数,因此如果您的函数很大并且使用各种不同的数组大小调用它,这可能会很昂贵。你可以使用它作为这样的函数的包装器:
void myFunction(double * arr, int R, int C)
{
arr[x * C + y] = 5;
etc...
}
它将数组视为一维,并使用算术来计算索引的偏移量。在这种情况下,您可以像这样定义模板:
template<int C, int R>
void myFunction(double (&myArray)[R][C])
{
myFunction(*myArray, R, C);
}
答案 4 :(得分:15)
感到惊讶的是,还没有人提到这一点,但你可以简单地模拟任何支持[] []语义的2D。
template <typename TwoD>
void myFunction(TwoD& myArray){
myArray[x][y] = 5;
etc...
}
// call with
double anArray[10][10];
myFunction(anArray);
适用于任何2D&#34;阵列式的&#34;数据结构,例如std::vector<std::vector<T>>
,或用户定义的类型,以最大化代码重用。
答案 5 :(得分:10)
anArray[10][10]
不是指向指针的指针,它是一个连续的内存块,适合存储100个double类型的值,编译器知道如何解决因为你指定了维度。您需要将其作为数组传递给函数。您可以省略初始尺寸的大小,如下所示:
void f(double p[][10]) {
}
但是,这不允许您传递最后一个维度为十的数组。
C ++中最好的解决方案是使用std::vector<std::vector<double> >
:它几乎同样有效,而且非常方便。
答案 6 :(得分:8)
单维数组衰减到指向数组中第一个元素的指针指针。当2D阵列衰减到指向第一行的指针时。所以,函数原型应该是 -
void myFunction(double (*myArray) [10]);
我希望std::vector
优于原始数组。
答案 7 :(得分:8)
你可以这样做......
#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;
}
您的输出如下......
11.5 12.5
13.5 14.5
答案 8 :(得分:2)
这是向量矩阵示例的向量
#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 8
9 1 2 3
0 0 0 0
0 0 0 0
0 0 0 0
答案 9 :(得分:1)
传递多维数组的一个重要方面是:
First array dimension
无需指定。Second(any any further)dimension
。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.使用单个指针: 在这种方法中,我们必须在传递给函数时对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;
}`
答案 10 :(得分:1)
我们可以使用几种方法将2D数组传递给函数:
使用单指针,我们必须对2D数组进行类型转换。
#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;
}
使用双指针,通过这种方式,我们还对2d数组进行了类型转换
#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;
}
答案 11 :(得分:0)
您可以在C ++中使用模板工具来执行此操作。我做了这样的事情:
template<typename T, size_t col>
T process(T a[][col], size_t row) {
...
}
这种方法的问题在于,对于您提供的col的每个值,使用模板实例化新的函数定义。 所以,
int some_mat[3][3], another_mat[4,5];
process(some_mat, 3);
process(another_mat, 4);
将模板实例化两次以生成2个函数定义(一个col = 3,另一个col = 5)。
答案 12 :(得分:0)
如果要将int a[2][3]
传递给void func(int** pp)
,则需要执行以下辅助步骤。
int a[2][3];
int* p[2] = {a[0],a[1]};
int** pp = p;
func(pp);
由于可以隐式指定第一个[2]
,因此可以进一步简化为。
int a[][3];
int* p[] = {a[0],a[1]};
int** pp = p;
func(pp);
答案 13 :(得分:0)
如果您要将动态大小的二维数组传递给函数,则可以使用一些指针。
void func1(int *arr, int n, int m){
...
int i_j_the_element = arr[i * m + j]; // use the idiom of i * m + j for arr[i][j]
...
}
void func2(){
...
int arr[n][m];
...
func1(&(arr[0][0]), n, m);
}
答案 14 :(得分:0)
您可以省略最左侧的尺寸,因此有两种选择:
import { Component, Prop } from '@stencil/core';
@Component({
tag: 'my-component',
styleUrl: 'my-component.css',
shadow: true
})
export class MyComponent {
@Prop() first: string;
@Prop() last: string;
divElement!: HTMLElement; // define a variable for html element
getElementHere() {
this.divElement // this will refer to your <div> element
}
render() {
return (
<div ref={(el) => this.divElement= el as HTMLElement}> // add a ref here
Hello, World! I'm {this.first} {this.last}
</div>
);
}
}
与指针相同:
void f1(double a[][2][3]) { ... }
void f2(double (*a)[2][3]) { ... }
double a[1][2][3];
f1(a); // ok
f2(a); // ok
C ++标准允许将N维数组衰减为指向N-1维数组的指针,因为您可能会丢失最左侧的维,并且仍然能够正确访问N个数组元素-1维信息。
中的详细信息尽管,数组和指针并不相同:数组可以衰减为指针,但是指针并不携带有关其指向的数据的大小/配置的状态。 / p>
// compilation error: cannot convert ‘double (*)[2][3]’ to ‘double***’
// double ***p1 = a;
// compilation error: cannot convert ‘double (*)[2][3]’ to ‘double (**)[3]’
// double (**p2)[3] = a;
double (*p3)[2][3] = a; // ok
// compilation error: array of pointers != pointer to array
// double *p4[2][3] = a;
double (*p5)[3] = a[0]; // ok
double *p6 = a[0][1]; // ok
是指向包含字符指针的存储块的指针,它们本身指向字符的存储块。 char **
是一个包含字符的单个存储块。这会影响编译器如何翻译代码以及最终性能如何。
答案 15 :(得分:-1)
如果使用 vector