提问者:小点点

将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]。 我怎么能这么做呢?


共3个答案

匿名用户

将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.通过引用传递

    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++中,通过引用传递数组而不丢失维度信息可能是最安全的,因为不必担心调用方传递不正确的维度(当不匹配时编译器标记)。 但是,对于动态(自由存储)数组,这是不可能的; 它只适用于自动数组(通常是堆栈生存数组),也就是说,维数应该在编译时就知道。

    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)传递,而不是通过decayprocess_2D_array_pointer(a)传递第一个元素的地址。

    这些都是从C继承的,但安全性较低,编译器无法检查,以保证调用方传递所需的维度。 函数只依赖调用方作为维度传入的内容。 这些方法比上述方法更灵活,因为不同长度的数组可以一成不变地传递给它们。

    需要记住的是,在C中不存在将数组直接传递给函数的情况[而在C++中,它们可以作为引用(1)传递]; (2)将指针传递到数组而不是数组本身。 始终按原样传递数组就变成了指针复制操作,这是因为数组会变成指针的特性。

    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的数组的指针时,编译器可以标记。 第一个维度是变化部分,可以省略。 请参阅此处,了解为什么只允许省略第一个维度的基本原理。

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

    相关问题


    MySQL Query : SELECT * FROM v9_ask_question WHERE 1=1 AND question regexp '(2d|数组|递给|c++|函数)' ORDER BY qid DESC LIMIT 20
    MySQL Error : Got error 'repetition-operator operand invalid' from regexp
    MySQL Errno : 1139
    Message : Got error 'repetition-operator operand invalid' from regexp
    Need Help?