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

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

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

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

Ответ 1

int* test();

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

std::vector< int > test();

ИЗМЕНИТЬ
Я уточню некоторые моменты. Поскольку вы упомянули С++, я поеду с операторами new[] и delete[], но это то же самое с malloc/free.

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

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.

Так как это С++, ` std::vector <T> является широко используемым решением:

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
}

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

Ответ 2

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

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

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

  • std::array<> (введено с С++ 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 для возвращаемых данных иногда может избежать копирования, но обычно вы можете просто полагаться на Оптимизацию возвращаемого значения или - для vector, но не array - перемещать семантику (введенную с помощью С++ 11).

Если вы действительно хотите использовать встроенный массив (в отличие от класса стандартной библиотеки, называемого 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();
}

Начиная с вышеизложенного, если вы застряли с использованием С++ 03, вы можете обобщить его на нечто более близкое к С++ 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++ используют "умные указатели", которые обеспечивают удаление, когда указатели (указатели) на объект покидают свои области. С С++ 11:

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

Если вы застряли на С++ 03, лучший вариант - посмотреть, доступна ли библиотека ускорения на вашем компьютере: она предоставляет 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...
}

Ответ 3

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

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

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

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;
}

Ответ 4

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

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

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

Ответ 5

"как я могу вернуть массив в С++-методе и как его объявить? 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;