Как передать трехмерные массивы с помощью тройных указателей? - PullRequest
0 голосов
/ 12 июня 2019

Это действительно возможно?

Я знаю, как передавать двумерные массивы с помощью двойного указателя. И, насколько я понимаю, это должно быть и для трехмерных массивов. Но я бы хотел оказаться неправым. Этот вопрос наверняка покажет, как интерпретируются массивы.

Дело в том, что трехмерный массив - это непрерывный блок, а не какой-то массив указателей на более мелкие куски.

Эта программа выдаёт мне ошибку:

#include <iostream>

using namespace std;

void display(int ***arr, int l, int m, int n)
{
    for(int i=0; i<l; i++)
        for(int j=0; j<m; j++)
            for(int k=0; k<n; k++)
                cout << *(*(*(arr+i)+j)+k) << endl;
}

int main()
{
    int arr[][2][2] = {{{1,2},{3,4}},{{10,20},{30,40}}};
    display((int***)arr,2,2,2);
}

OUTPUT

test.cpp:17:19: error: cannot convert 'int (*)[2][2]' to 'int***' for argument '1' to 'void display(int***, int, int, int)'
  display(arr,2,2,2);
                   ^

2D-массивы переданы двойному указателю Я верю, что могу сделать что-то похожее на 3D-массивы, но это слишком плохо для чтения

#include <iostream>

using namespace std;

void display(int **arr, int m, int n)
{
    for(int i=0; i<m; i++)
        for(int j=0; j<n; j++)
            cout << *(*(arr+i)+j) << " " << arr[i][j] << endl;
}

int main()
{
    int arr[][3] = {{1,2,3},{4,5,6}};
    int *temp[2];
    for(int i=0; i<2; i++)
        temp[i] = *(arr+i);
    display(temp,2,3);
}
OUTPUT
1 1
2 2
3 3
4 4
5 5
6 6

Ответы [ 4 ]

1 голос
/ 12 июня 2019

То, что вы делаете для двумерных массивов, правильно, потому что вы создали вспомогательный массив указателей и передаете этот массив указателей как int **.Даже для двумерных массивов этот

void display(int **arr, int m, int n);
...

int arr[][3] = {{1,2,3},{4,5,6}};
display(arr,2,3);            // WRONG! use a 2D array as an array of pointers

был бы неправильным.

И в любом случае стандарт C ++ недружелюбен к многомерным массивам: нет способа написать строго согласованную передачу программымногомерные массивы неизвестного измерения.Многие компиляторы принимают его как расширения, но он может быть непереносимым на других компиляторах.

Идиоматический способ - использовать только одномерные массивы в качестве базовой структуры данных и предоставлять методы для обработки его как многомерного контейнер путем внутреннего вычисления индекса.


Кстати, я пытался построить многомерный непрерывный контейнер с произвольными измерениями времени выполнения, соблюдая все ограничения стандартных контейнеров, иОтказался после осознания того, что стандарт не позволил этого: невозможно построить хороший итератор над объектом, который не содержит своих собственных данных.Вот моя лучшая попытка .Ответы и комментарии объясняют, почему это безнадежно.

0 голосов
/ 12 июня 2019

Полагаю, я могу сделать что-то похожее на 3D-массивы, но это слишком плохо для чтения.

Да, как объяснили нм в ихcomment

В своем 2D-коде вы создали совершенно новый массив указателей, заполнили его и передали его в свою функцию вместо исходного 2D-массива.В вашем 3D-коде вы не пытались ничего подобного.

Поскольку вопрос помечен как C ++, мы можем использовать другой набор инструментов, чем кодировщики языка C.

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

#include <iostream>
#include <iomanip>

template <class T, size_t L, size_t M, size_t N>
void display( T const (&arr)[L][M][N], int width )
//                    ^^^^^^
{
    for (size_t i = 0; i < L; ++i) {
        for (size_t j = 0; j < M; ++j) {
            for (size_t k = 0; k < N; ++k) {
                std::cout << std::setw(width) << arr[i][j][k];
            }
            std::cout << '\n';
        }
        std::cout << '\n';
    }
}

int main()
{
    int arr[3][2][4] = {
        { {1,2,3,4},
          {5,6,7,8}
        },
        { {10,20,30,40},
          {50,60,70,80}
        },
        { {100,200,300,400},
          {500,600,700,800}
        }
    };

    display(arr, 5);
}

Live, ЗДЕСЬ .

Следующим шагом, конечно, будет написание класса, который инкапсулирует концепцию многомерного массива.

0 голосов
/ 12 июня 2019

Когда вы объявляете массив локально int arr[][2][2], компилятор создает экземпляр одномерного вектора и «запоминает», что такое смещение для получения правильного индекса.

Также локальные массивы хранятся в стеке, который не являетсяхорошо, если вам нужны большие матрицы.Другое свойство int arr[][2][2] заключается в том, что, когда вы пытаетесь передать его в качестве аргумента функции, int arr [] [2] [2] имеет тип .Вы должны указать все размеры.

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

В заключение:

  • Я бы использовал локальные массивы, когда требуемая память мала, и мне не нужны указатели.Локальные массивы хороши, если вы хотите избежать использования кучи.
  • Использование pointersm new / delete или malloc / free разрешено, но я думаю, что лучше использовать стандартную библиотеку в C ++, поэтому я бы использовал std ::вектор во всех других сценариях.
0 голосов
/ 12 июня 2019

Хотя вы можете передать 1-D массив, как этот

void pass1Darray(int a[])
    {
        statements;
    }

    int main()
    {
        int a[10];
        pass1Darray(a);
    }

Фактически, компилятор будет видеть int a[] как int* a, и это является причиной, почему люди задаются вопросом, возможно ли передать двумерный массив с помощью pointer_to_pointer.

Но это не имеет смысла!

Если вы хотите передать двумерный массив bob[5][10], вы можете увидеть bob как массив, а его элемент - массив, и передать его следующим образом

void pass2Darray( int (*array) [10] )  // it means you pass a pointer which points to a int[10]
{
    statements;
}

int main()
{
    int bob[5][10];
    pass2Darray(bob);
}

Речь идет о передаче двумерного массива.

Кстати, английский не является моим родным языком, и я тоже начинающий с ++.

Если что-то не так, пожалуйста, дайте мне знать, спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...