Возвращение многомерного массива из функции - PullRequest
22 голосов
/ 15 сентября 2010

Как мне вернуть многомерный массив, хранящийся в поле 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** взамен

Ответы [ 7 ]

23 голосов
/ 15 сентября 2010

Двумерный массив не распадается на указатель на указатель на целые.Он распадается на указатель на массивы целых чисел, то есть только первое измерение распадается на указатель.Указатель указывает не на указатели типа 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

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

17 голосов
/ 15 сентября 2010

Существует два возможных типа, которые вы можете вернуть для предоставления доступа к вашему внутреннему массиву.Старый стиль 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;
}

Преимущество версии C ++ состоит в том, чтофактический тип сохраняется, и это означает, что фактический размер массива известен на стороне вызывающего.

7 голосов
/ 15 сентября 2010

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

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

int (*Myclass::get_array())[5] {
    return myarray;
}
2 голосов
/ 10 января 2019

Проще было бы decltype(auto) (начиная с C ++ 14)

decltype(auto) get_array() { return (myarray); } // Extra parents to return reference

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

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

тогда введите typedef way:

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> (начиная с C ++ 11) будет более естественнымсинтаксис.

2 голосов
/ 15 сентября 2010

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

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

В любом случае, вы не можете возвращать массивы из функций, но вы можете вернуть указатель на первый элемент.Каков первый элемент массива 5x5 целых?Массив из 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> вместо?

1 голос
/ 15 сентября 2010

Мне удалось заставить эту функцию работать в C ++ 0x, используя автоматическое определение типа. Тем не менее, я не могу заставить это работать без этого. Собственные массивы C не очень хорошо поддерживаются в 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.

0 голосов
/ 15 сентября 2010

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

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