Возвращение многомерного массива из функции
Как вернуть многомерный массив, хранящийся в 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**
взамен
Ответы
Ответ 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;
}