Как передать динамический 2-D массив в функцию в C++

Я пытаюсь передать динамический 2-D массив в функцию, и он выдает ошибку. Я попытался явно указать размеры массива, и это сработало, но динамический не работает, никаких указателей (каламбур не предназначен)

#include <iostream>
#include <vector>

using namespace std;

void print_2d_array(int arr_size, int (*arr)[5]){
    for(int i = 0; i < arr_size; ++i){
        for(int j = 0; j < arr_size; ++j)
            cout << arr[i][j] << "\t";
        cout << endl;
    }
}

int main(){
    vector<int> x{10,15,20,30,40};
    int arr[x.size()][x.size()];

    for(int i = 0; i < x.size(); ++i)
        arr[i][i] = 0;

    print_2d_array(5, arr);
    return 0;
}

Я перепробовал все три метода, которые были подробно описаны здесь. Передача 2D массива в C

Если вместо создания массива, как показано выше, я использую что-то вроде

arr[5][5];

это работает как ожидалось. Я получаю следующую ошибку

error: cannot convert ‘int (*)[(<anonymous> + 1)]’ to ‘int (*)[5]’ for argument ‘2’ 
to ‘void print_2d_array(int, int (*)[5])’

print_2d_array(5, обр);

2 ответа

Решение

Массив переменной длины (VLA) не является частью стандарта C++. Он является частью стандарта C99 и обычно реализуется как расширение для C++ в различных компиляторах.

Обычно нормально использовать VLA в программе на C++, когда вы выделяете массив. Но у вас будут проблемы, когда вам нужно будет передать массив, потому что нет типа аргумента VLA, чтобы вы могли передавать его в качестве аргументов функциям в C++. (Вот почему, когда вы вручную вставляете функцию, код работает нормально, что позволяет избежать передачи массива в функцию.) Вы должны передать массив как указатель на функцию и, возможно, использовать reinterpret_cast до и внутри функции для преобразования VLA в указатель и преобразования его обратно. Это просто ужасный код.

При кодировании на C++ просто используйте идиоматический способ C++. Поскольку вы уже используете vectorВы можете просто использовать vector<vector<int>> (vector<vector<int> > если не с использованием C++11, а из способа инициализации xвы используете C++11) в качестве двумерного массива. Ваш код должен быть изменен, как показано ниже:

#include <iostream>
#include <vector>

using namespace std;

void print_2d_array(int arr_size, vector<vector<int>> &arr){
    for(int i = 0; i < arr_size; ++i){
        for(int j = 0; j < arr_size; ++j)
            cout << arr[i][j] << "\t";
        cout << endl;
    }
}

int main(){
    vector<int> x{10,15,20,30,40};
    vector<vector<int>> arr(x.size(), vector<int>(x.size()));

    // No need to use this to initialize:
    // for(int i = 0; i < sizeof(x); ++i)
    //     arr[i][i] = 0;

    print_2d_array(5, arr);
    return 0;
}

Обратите внимание, что это также исправило вашу проблему arr не был правильно инициализирован.

Если вы собираетесь использовать C, то VLA полностью в порядке, и это будет так (и не то, чтобы я не исправил вашу инициализацию, которая только инициализировала диагональные элементы. Вы должны использовать компилятор C, а не C++, чтобы скомпилируйте это.):

#include <stdio.h>

void print_2d_array(int arr_size, int arr[][arr_size]){
    for(int i = 0; i < arr_size; ++i){
        for(int j = 0; j < arr_size; ++j)
            printf("%d\t", arr[i][j]);
        printf("\n");
    }
}

int main(){
    int x[] = {10,15,20,30,40};
    int arr[sizeof(x)][sizeof(x)];

    // bad initialization:
    for(int i = 0; i < sizeof(x); ++i)
        arr[i][i] = 0;

    print_2d_array(5, arr);
    return 0;
}

Хорошо, если вы решили использовать C++, но не любите vector, следующая простейшая вещь - использовать примитивные указатели, что не рекомендуется.

#include <iostream>
#include <vector>

using namespace std;

void print_2d_array(int arr_size, int **arr){
    for(int i = 0; i < arr_size; ++i){
        for(int j = 0; j < arr_size; ++j)
            cout << arr[i][j] << "\t";
        cout << endl;
    }
}

int main(){
    vector<int> x {10,15,20,30,40};
    int **arr = new int*[x.size()];
    for (int i = 0; i < x.size(); ++i) {
        arr[i] = new int[x.size()];
        for (int j = 0; j < x.size(); ++j) {
            arr[i][j] = 0;
        }
    }

    print_2d_array(5, arr);

    for (int i = 0; i < x.size(); ++i) {
        delete[] arr[i];
    }
    return 0;
}

Сохраните свои проблемы и используйте контейнеры. Вы используете современный C++.

(Ответ предполагает, что вы не можете определить размер массива перед запуском. Хотя в вашем примере это не так - размер должен быть 5, и нет причин использовать VLA.)

Прежде всего,

int arr[x.size()][x.size()];

не является допустимым C++. Размеры массива должны быть известны во время компиляции.

Если вы используете компилятор, который поддерживает массивы переменной длины, в качестве расширения, вы можете использовать этот оператор. Но тогда тип переменной не int (*)[5]что и ожидается print_2d_array,

Вы можете использовать вложенный std::array если вы знаете размеры во время компиляции.

Вы можете использовать вложенный std::vector если нужно вычислить размеры во время выполнения.

Обновление в ответ на комментарий ОП

Возьмите упрощенную версию программы.

#include <iostream>
#include <vector>

using namespace std;

int main(){
    vector<int> x{10,15,20,30,40};
    int arr[x.size()][x.size()];
    return 0;
}

Команда для компиляции:

g++ -Wall -std=c++11    socc.cc   -o socc -pedantic

Ошибки / предупреждения:

socc.cc: In function ‘int main()’:
socc.cc:8:31: warning: ISO C++ forbids variable length array ‘arr’ [-Wvla]
     int arr[x.size()][x.size()];
                               ^
socc.cc:8:31: warning: ISO C++ forbids variable length array ‘arr’ [-Wvla]
socc.cc:8:9: warning: unused variable ‘arr’ [-Wunused-variable]
     int arr[x.size()][x.size()
Другие вопросы по тегам