Передача двумерного массива в функцию

Рейтинг: 2Ответов: 3Опубликовано: 15.09.2014

Как я знаю, имя массива и указателя тождественны в С++. Из этого следует, что можно инициализировать указатель, а работать с ним, как с именем массива, добавив индекс (квадратный скобки) или смещение к имени массива и круглые скобки со звёздочкой... Но не в этом суть. Я пробовал ввести передачу в функцию двумерного массива (столбы и строки) - не вышло. Очевидно, что где-то вкралась ошибка. Вот код:

#include "stdafx.h"
#include <iostream>

using namespace std;

const int size1 = 3;
const int size2 = 4;
int arr[size1[size2 = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
    
void arr_fun (int arr[[size2, int size1);

void main ()
{
    arr_fun (arr[[size2, size1);
    system ("pause");
}
void arr_fun (int arr[[size2, size1)
{
    for (int i=0; i<size1; i++)
    {
        for (int j=0; j<size2; j++)
        {
    cout<<"arr["<<i<<": "<<arr[i[j<<endl;
        }
    }
}

Хотя бы дайте общие понятия по логике передачи адреса двумерного и более массива в функцию, а дальше я сам попробую написать =)

Ответы

▲ 2

@00Brain00, Вы пишете

 Хотя бы дайте общие понятия по логике передачи адреса двумерного и более массива в функцию

Элементы классических массивов (независимо от количества измерений) размещаются в памяти последовательно.

Поэтому в общем случае для доступа к элементу с заданными координатами в функцию надо передать адрес первого элемента и размер всех измерений (кроме "верхнего"). В таком случае массив можно рассматривать как одномерный и вычислять индекс нужного элемента в нем.

Для двумерного массива получаем:

T get_elem (T *arr, int cols, int n_row, int n_col) // T это тип (в Си можно определять в #define, например, #define T double)
{  
    return arr[n_row * cols + n_col];
}

Для трехмерного

T get_elem (T *arr, int rows, int cols, int i, int j, int k)
{  
    return arr[i * rows * cols + j * cols + k];
}

Далее аналогично.

Если Вы знаете (при написании программы, т.е. знаете константы) размер всех измерений массива, кроме, может быть, самого "верхнего", то компилятор упрощает Вам жизнь и для трехмерного int arr[][4][3] можно написать функцию так:

 int get_elem (int arr[][4][3], int i, int j, int k) {
    return arr[i][j][k];
 }

и, разместив в main подходящие массивы, написать что-то вроде

  int a[10][4][3], // 10 плоскостей (матриц), каждая из 4-х строк по 3 элемнта
      b[3][4][3];
    ...
  printf ("%d\n", get_elem(a, 2, 2, 2) + get_elem(b, 2, 2, 2));

Не забывайте, что все индексы с нуля.

▲ 1

Если размеры массива являются константами времени компиляции (как в вашем примере), то никакого специального огорода с указателями городить не надо

const int size1 = 3;
const int size2 = 4;

void arr_fun(const int arr[size1][size2])
{
    for (int i = 0; i < size1; i++)
        for (int j = 0; j < size2; j++)
           cout << arr[i][j] << endl;
}

...
int arr[size1][size2] = { ... };
arr_fun(arr);

Вот и все. Никаких трехэтажных манипуляций с указателями тут не нужно в принципе.

В С++ я бы посоветовал даже передавать массив "по ссылке", чтобы заставить компилятор выполнять жесткую проверку обоих размеров

void arr_fun(const int (&arr)[size1][size2])
{
    for (int i = 0; i < size1; i++)
        for (int j = 0; j < size2; j++)
           cout << arr[i][j] << endl;
}
▲ 1

В очень ограниченном случае можно делать так, как вы хотите:

#include <iostream>

template <typename T, int n, int m>
void print(const T (&xs)[n][m]) {
    using namespace std;

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            cout << xs[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}

int main() {
    int as[2][2] = {
        {1, 2},
        {3, 4},
    };

    float bs[2][3] = {
        {2.f, 0.5f, 100.f},
        {1.f, 0.2f, 3.14f},
    };

    print(as);
    print(bs);
}

Но это значит, что размер массива должен быть известен на этапе компиляции (точнее, быть constexpr), т.к. он является частью типа функции.

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