将2D数组传递给C ++函数
我有一个函数,我想作为一个参数,可变大小的二维数组。
到目前为止,我有这样的:
void myFunction(double** myArray){
myArray[x][y] = 5;
etc...
}
我已经在我的代码中的其他地方声明了一个数组:
double anArray[10][10];
但是,调用myFunction(anArray)
会给我一个错误。
我不想在传入数组时复制数组。在myFunction
所做的任何更改都会改变anArray
的状态。 如果我理解正确,我只想传入一个指向2D数组的指针。 该功能还需要接受不同大小的数组。 例如, [10][10]
和[5][5]
。 我怎样才能做到这一点?
有三种方法将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.通过参考
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.通过指针传递
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)将指针传递给数组,而不是数组本身。 总是按原样传递一个数组变成了一个指针复制操作,这是由数组的性质衰减为一个指针所促成的。
3.传递(value)一个指向衰减类型的指针
// 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个整数数组的单个指针,而这个语法看起来像是一个二维数组,但是与10个整数数组是相同的指针。 这里我们知道单行中元素的数量(即列大小,这里是10),但行数是未知的,因此可以作为参数传递。 在这种情况下,由于编译器可以标记何时传递了第二维不等于10的数组的指针,因此存在一些安全性。 第一个维度是变化的部分,可以省略。 在这里看到为什么只允许第一个维度被省略的理由。
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)是最不安全的选项,因为它几乎没有任何类型检查并且最不方便。 一个人不能合法地将二维数组传递给这个函数; 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);
因为它可能会导致由于阵列变平而导致未定义的行为。 在这个方法中传递数组的正确方法将我们带到了不方便的部分,即我们需要一个额外的(代理)指针数组,每个指向数组的元素都指向实际的,即将通过的数组的相应行; 这个代理被传递给函数(见下文)。 所有这些都是为了完成与上述更安全,更清洁和更快的方法相同的工作。
这里有一个驱动程序来测试上述功能:
#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的第一个建议的修改,可以使用模板来使该函数接受多维数组变量(而不是存储必须被管理和删除的指针数组):
template <size_t size_x, size_t size_y>
void func(double (&arr)[size_x][size_y])
{
printf("%pn", &arr);
}
int main()
{
double a1[10][10];
double a2[5][5];
printf("%pn%pnn", &a1, &a2);
func(a1);
func(a2);
return 0;
}
这些打印语句表明数组已通过引用传递(通过显示变量的地址)
链接地址: http://www.djcxy.com/p/40651.html