将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

    上一篇: Passing a 2D array to a C++ function

    下一篇: Need help about 'new' operator in C++