Как вернуть массив из функции?

Как я могу вернуть массив из метода, и как я должен объявить его?

int[] test(void); // ??

5 ответов


int* test();

но было бы" больше C++ " использовать векторы:

std::vector< int > test();

редактировать
Я кое-что проясню. Поскольку вы упомянули C++, я пойду с new[] и delete[] операторов, но это аналог.

в первом случае вы напишете что-то вроде:

int* test() {
    return new int[size_needed];
}

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

int* theArray = test();
for (size_t i; i < ???; ++i) { // I don't know what is the array size!
    // ...
}
delete[] theArray; // ok.

лучшей подписью будет эта:

int* test(size_t& arraySize) {
    array_size = 10;
    return new int[array_size];
}

и ваш клиентский код теперь будет:

size_t theSize = 0;
int* theArray = test(theSize);
for (size_t i; i < theSize; ++i) { // now I can safely iterate the array
    // ...
}
delete[] theArray; // still ok.

поскольку это C++, ' std:: vector является широко используемым решением:

std::vector<int> test() {
    std::vector<int> vector(10);
    return vector;
}

теперь вам не нужно звонить delete[], так как он будет обрабатываться объектом, и вы можете безопасно повторить его с:

std::vector<int> v = test();
std::vector<int>::iterator it = v.begin();
for (; it != v.end(); ++it) {
   // do your things
}

что проще и более безопасный.


как я могу вернуть массив в методе c++ и как я должен его объявить? int [] test (void);??

это звучит как простой вопрос, но в C++ у вас есть довольно много вариантов. Во-первых, вы должны предпочесть...

  • std::vector<>, который динамически растет до того, сколько элементов вы сталкиваетесь во время выполнения, или

  • std::array<> (введено с C++11), который всегда сохраняет ряд элементов, указанных во время компиляции,

...поскольку они управляют памятью для вас, обеспечивая правильное поведение и значительно упрощая вещи:

std::vector<int> fn()
{
    std::vector<int> x;
    x.push_back(10);
    return x;
}

std::array<int, 2> fn2()  // C++11
{
    return {3, 4};
}

void caller()
{
    std::vector<int> a = fn();
    const std::vector<int>& b = fn(); // extend lifetime but read-only
                                      // b valid until scope exit/return

    std::array<int, 2> c = fn2();
    const std::array<int, 2>& d = fn2();
}

практика создания const ссылка на возвращаемые данные иногда может избежать копирования, но обычно вы можете просто положиться на оптимизацию возвращаемого значения или-for vector а не array - семантика перемещения (введена с C++11).

если вы действительно хотите использовать Ан встроенный array (в отличие от стандартного класса библиотеки array упомянутый выше), один из способов для вызывающего абонента зарезервировать пространство и сказать функции использовать его:

void fn(int x[], int n)
{
    for (int i = 0; i < n; ++i)
        x[i] = n;
}

void caller()
{
    // local space on the stack - destroyed when caller() returns
    int x[10];
    fn(x, sizeof x / sizeof x[0]);

    // or, use the heap, lives until delete[](p) called...
    int* p = new int[10];
    fn(p, 10);
}

другой вариант-обернуть массив в структуру, которая - в отличие от необработанных массивов-законна для возврата по значению из функции:

struct X
{
    int x[10];
};

X fn()
{
    X x;
    x.x[0] = 10;
    // ...
    return x;
}

void caller()
{
    X x = fn();
}

начиная с вышеизложенного, если вы застряли с помощью C++03, вы можете обобщить его на что-то ближе к C++11 std::array:

template <typename T, size_t N>
struct array
{
    T& operator[](size_t n) { return x[n]; }
    const T& operator[](size_t n) const { return x[n]; }
    size_t size() const { return N; }
    // iterators, constructors etc....
  private:
    T x[N];
};

другой вариант - чтобы вызываемая функция выделяла память в куче:

int* fn()
{
    int* p = new int[2];
    p[0] = 0;
    p[1] = 1;
    return p;
}

void caller()
{
    int* p = fn();
    // use p...
    delete[] p;
}

чтобы упростить управление объектами кучи, многие программисты на C++ используют "умные указатели", которые обеспечивают удаление, когда указатель(ы) на объект покидает свои области. С C++11:

std::shared_ptr<int> p(new int[2], [](int* p) { delete[] p; } );
std::unique_ptr<int[]> p(new int[3]);

если вы застряли на C++03, лучший вариант-посмотреть, доступна ли библиотека boost на вашем компьютере: она предоставляет boost::shared_array.

еще один вариант-иметь некоторую статическую память, зарезервированную fn(), хотя это не потокобезопасно, и означает каждый вызов fn() перезаписывает данные, замеченные любым, кто держит указатели от предыдущих вызовов. Тем не менее, это может быть удобно (и быстро) для простого однопоточного кода.

int* fn(int n)
{
    static int x[2];  // clobbered by each call to fn()
    x[0] = n;
    x[1] = n + 1;
    return x;  // every call to fn() returns a pointer to the same static x memory
}

void caller()
{
    int* p = fn(3);
    // use p, hoping no other thread calls fn() meanwhile and clobbers the values...
    // no clean up necessary...
}

невозможно вернуть массив из функции C++. 8.3.5[dcl.fct] / 6:

функции не должны иметь возвращаемого типа типа array или function[...]

наиболее часто выбираемыми альтернативами являются возврат значения типа класса, где этот класс содержит массив, например

struct ArrayHolder
{
    int array[10];
};

ArrayHolder test();

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

Э. Г.

int* test2()
{
    return new int[10];
}

int* test3()
{
    static int array[10];
    return array;
}

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

int (&test4())[10]
{
        static int array[10];
        return array;
}

int (*test5())[10]
{
        static int array[10];
        return &array;
}

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

поэтому сделайте ваш массив статическим или выделите память (или передайте ее, но ваша начальная попытка с параметром void). Для вашего метода я бы определил его так:

int *gnabber(){
  static int foo[] = {1,2,3}
  return foo;
}

" как я могу вернуть массив в методе c++ и как я должен его объявить? int [] test (void);??"

template <class X>
  class Array
{
  X     *m_data;
  int    m_size;
public:
    // there constructor, destructor, some methods
    int Get(X* &_null_pointer)
    {
        if(!_null_pointer)
        {
            _null_pointer = new X [m_size];
            memcpy(_null_pointer, m_data, m_size * sizeof(X));
            return m_size;
        }
       return 0;
    }
}; 

только для int

class IntArray
{
  int   *m_data;
  int    m_size;
public:
    // there constructor, destructor, some methods
    int Get(int* &_null_pointer)
    {
        if(!_null_pointer)
        {
            _null_pointer = new int [m_size];
            memcpy(_null_pointer, m_data, m_size * sizeof(int));
            return m_size;
        }
       return 0;
    }
}; 

пример

Array<float> array;
float  *n_data = NULL;
int     data_size;
if(data_size = array.Get(n_data))
{     // work with array    }

delete [] n_data;

пример для int

IntArray   array;
int       *n_data = NULL;
int        data_size;
if(data_size = array.Get(n_data))
{  // work with array  }

delete [] n_data;