Подтвердить что ты не робот

Возвращение многомерного массива из функции

Как вернуть многомерный массив, хранящийся в private поле моего класса?

class Myclass {
private:
   int myarray[5][5];
public:
   int **get_array();
};

// This does not work:
int **Myclass::get_array() {
    return myarray;
}

Я получаю следующую ошибку:

не может конвертировать int (*)[5][5] в int** взамен

4b9b3361

Ответ 1

Двумерный массив не распадается на указатель на указатель на int. Он распадается на указатель на массивы ints - то есть только первое измерение распадается на указатель. Указатель не указывает на int указатели, которые при инкрементном продвижении по размеру указателя, но массивы из 5 целых чисел.

class Myclass {
private:
    int myarray[5][5];
public:
    typedef int (*pointer_to_arrays)[5]; //typedefs can make things more readable with such awkward types

    pointer_to_arrays get_array() {return myarray;}
};

int main()
{
    Myclass o;
    int (*a)[5] = o.get_array();
    //or
    Myclass::pointer_to_arrays b = o.get_array();
}

Указатель на указатель (int**) используется, когда каждый подмассив распределяется отдельно (т.е. изначально у вас есть массив указателей)

int* p[5];
for (int i = 0; i != 5; ++i) {
    p[i] = new int[5];
}

Здесь мы имеем массив из пяти указателей, каждый из которых указывает на первый элемент в отдельном блоке памяти, всего 6 различных блоков памяти.

В двумерном массиве вы получаете единый непрерывный блок памяти:

int arr[5][5]; //a single block of 5 * 5 * sizeof(int) bytes

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

Ответ 2

Существует два возможных типа, которые вы можете вернуть, чтобы обеспечить доступ к вашему внутреннему массиву. Старый стиль C возвращал бы int *[5], так как массив легко распадается на указатель на первый элемент, который имеет тип int[5].

int (*foo())[5] {
   static int array[5][5] = {};
   return array;
}

Теперь вы также можете вернуть правильную ссылку на внутренний массив, самый простой синтаксис - через typedef:

typedef int (&array5x5)[5][5];
array5x5 foo() {
   static int array[5][5] = {};
   return array;
}

Или немного более громоздко без typedef:

int (&foo())[5][5] {
   static int array[5][5] = {};
   return array;
}

Преимущество версии С++ заключается в том, что фактический тип поддерживается, а это означает, что фактический размер массива известен со стороны вызывающих абонентов.

Ответ 3

Чтобы вернуть указатель на массив массива, нужен тип int (*)[5], а не int **:

class Myclass {
private:
    int myarray[5][5];
public:
    int (*get_array())[5];
};

int (*Myclass::get_array())[5] {
    return myarray;
}

Ответ 4

Как вернуть многомерный массив, скрытый в частном поле?

Если он должен быть скрыт, почему вы его возвращаете в первую очередь?

В любом случае вы не можете возвращать массивы из функций, но вы можете вернуть указатель на первый элемент. Что такое первый элемент массива 5x5 из ints? Массив из 5 целых чисел, конечно:

int (*get_grid())[5]
{
    return grid;
}

В качестве альтернативы вы можете вернуть весь массив по ссылке:

int (&get_grid())[5][5]
{
    return grid;
}

... приветствуем синтаксис аддитора C; -)

Могу я предложить вместо std::vector<std::vector<int> > или boost::multi_array<int, 2>?

Ответ 5

Мне удалось заставить эту функцию работать в С++ 0x, используя автоматический вывод типа. Однако я не могу заставить это работать без этого. Родные C массивы не очень хорошо поддерживаются в С++ - их синтаксис чрезвычайно отвратителен. Вы должны использовать класс-оболочку.

template<typename T, int firstdim, int seconddim> class TwoDimensionalArray {
    T data[firstdim][seconddim];
public:
    T*& operator[](int index) {
        return data[index];
    }
    const T*& operator[](int index) const {
        return data[index];
    }
};
class Myclass {
public:
    typedef TwoDimensionalArray<int, 5, 5> arraytype;
private:
    arraytype myarray;
public:
    arraytype& get_array() {
        return myarray;
    }
};

int main(int argc, char **argv) {
    Myclass m;
    Myclass::arraytype& var = m.get_array();
    int& someint = var[0][0];
}

Этот код компилируется просто отлично. Вы можете получить предварительно написанный класс-оболочку внутри Boost (boost:: array), который поддерживает весь shebang.

Ответ 6

Проще будет decltype(auto) (начиная с С++ 14)

decltype(auto) get_array() { return myarray; }

затем decltype (начиная с С++ 11) (хотя член должен быть объявлен перед методом)

auto get_array() -> decltype((this->myarray)) { return myarray; }
// or
auto get_array() -> decltype(this->myarray)& { return myarray; }

затем напечатайте путь:

using int2D = int[5][5]; // since C++11
// or
typedef int int2D[5][5];

int2D& get_array() { return myarray; }

так как обычный синтаксис очень безобразен:

int (&get_array())[5][5] { return myarray; }

Использование std::array<std::array<int, 5>, 5> (начиная с С++ 11) будет иметь более естественный синтаксис.

Ответ 7

Измените свой int на int [] [] или попробуйте вместо этого использовать int [,]?

Ответ 8

int **Myclass::get_array() { 
 return (int**)myarray; 
}