为了账号安全,请及时绑定邮箱和手机立即绑定

将2D数组传递给C ++函数

将2D数组传递给C ++函数

C++ C
心有法竹 2019-05-28 17:39:07
将2D数组传递给C ++函数我有一个函数,我想作为一个参数,一个可变大小的2D数组。到目前为止我有这个:void myFunction(double** myArray){      myArray[x][y] = 5;      etc...}我在代码中的其他地方声明了一个数组:double anArray[10][10];但是,调用myFunction(anArray)给了我一个错误。当我传入数组时,我不想复制数组。所做的任何更改都myFunction应该改变数据的状态anArray。如果我理解正确,我只想作为参数传入指向2D数组的指针。该函数还需要接受不同大小的数组。例如,[10][10]和[5][5]。我怎样才能做到这一点?
查看完整描述

4 回答

?
开满天机

TA贡献1786条经验 获得超13个赞

将2D数组传递给函数有三种方法:

  1. 该参数是2D数组

    int array[10][10];void passFunc(int a[][10]){
        // ...}passFunc(array);
  2. 该参数是一个包含指针的数组

    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);
  3. 该参数是指向指针的指针

    int **array;array = new int *[10];for(int i = 0; i <10; i++)
        array[i] = new int[10];void passFunc(int **a){
        // ...}passFunc(array);


查看完整回答
反对 回复 2019-05-28
?
守着一只汪

TA贡献1872条经验 获得超3个赞

固定尺寸

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.传递(值)指向衰减类型的指针

// int array[][10] is just fancy notation for the same thingvoid 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的数组的指针,因此存在一些安全性。第一个维度是变化的部分,可以省略。请参阅此处了解为什么只允许省略第一维的原因。

4.通过指针指向指针

// int *array[10] is just fancy notation for the same thingvoid 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谴责通常的做法,int x[5][10]; process_pointer_2_pointer((int**)&x[0][0], 5, 10);因为它可能会因阵列扁平化而导致未定义的行为。在这种方法中传递数组的正确方法将我们带到了不方便的部分,即我们需要一个额外的(代理)指针数组,其每个元素指向实际的,要传递的数组的相应行; 然后将这个代理传递给函数(见下文); 这一切都是为了完成与上述方法相同的工作,这些方法更安全,更清洁,也许更快。

这是一个测试上述功能的驱动程序:

#include <iostream>// copy above functions hereint 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**}


查看完整回答
反对 回复 2019-05-28
?
守候你守候我

TA贡献1802条经验 获得超10个赞

对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语句用于显示数组是通过引用传递的(通过显示变量的地址)


查看完整回答
反对 回复 2019-05-28
?
慕哥6287543

TA贡献1831条经验 获得超10个赞

您可以创建这样的函数模板:

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);}


查看完整回答
反对 回复 2019-05-28
  • 4 回答
  • 0 关注
  • 605 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信