How to return an array from a function?

2019-01-01 11:00发布

How can I return an array from a method, and how must I declare it?

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

5条回答
何处买醉
2楼-- · 2019-01-01 11:22

"how can i return a array in a c++ method and how must i declare it? 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;
    }
}; 

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

example

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

delete [] n_data;

example for int

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

delete [] n_data;
查看更多
步步皆殇っ
3楼-- · 2019-01-01 11:26

It is not possible to return an array from a C++ function. 8.3.5[dcl.fct]/6:

Functions shall not have a return type of type array or function[...]

Most commonly chosen alternatives are to return a value of class type where that class contains an array, e.g.

struct ArrayHolder
{
    int array[10];
};

ArrayHolder test();

Or to return a pointer to the first element of a statically or dynamically allocated array, the documentation must indicate to the user whether he needs to (and if so how he should) deallocate the array that the returned pointer points to.

E.g.

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

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

While it is possible to return a reference or a pointer to an array, it's exceedingly rare as it is a more complex syntax with no practical advantage over any of the above methods.

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

int (*test5())[10]
{
        static int array[10];
        return &array;
}
查看更多
荒废的爱情
4楼-- · 2019-01-01 11:31

Well if you want to return your array from a function you must make sure that the values are not stored on the stack as they will be gone when you leave the function.

So either make your array static or allocate the memory (or pass it in but your initial attempt is with a void parameter). For your method I would define it like this:

int *gnabber(){
  static int foo[] = {1,2,3}
  return foo;
}
查看更多
闭嘴吧你
5楼-- · 2019-01-01 11:34

how can i return a array in a c++ method and how must i declare it? int[] test(void); ??

This sounds like a simple question, but in C++ you have quite a few options. Firstly, you should prefer...

  • std::vector<>, which grows dynamically to however many elements you encounter at runtime, or

  • std::array<> (introduced with C++11), which always stores a number of elements specified at compile time,

...as they manage memory for you, ensuring correct behaviour and simplifying things considerably:

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

The practice of creating a const reference to the returned data can sometimes avoid a copy, but normally you can just rely on Return Value Optimisation, or - for vector but not array - move semantics (introduced with C++11).

If you really want to use an inbuilt array (as distinct from the Standard library class called array mentioned above), one way is for the caller to reserve space and tell the function to use it:

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

Another option is to wrap the array in a structure, which - unlike raw arrays - are legal to return by value from a function:

struct X
{
    int x[10];
};

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

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

Starting with the above, if you're stuck using C++03 you might want to generalise it into something closer to the 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];
};

Another option is to have the called function allocate memory on the heap:

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

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

To help simplify the management of heap objects, many C++ programmers use "smart pointers" that ensure deletion when the pointer(s) to the object leave their scopes. With C++11:

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

If you're stuck on C++03, the best option is to see if the boost library is available on your machine: it provides boost::shared_array.

Yet another option is to have some static memory reserved by fn(), though this is NOT THREAD SAFE, and means each call to fn() overwrites the data seen by anyone keeping pointers from previous calls. That said, it can be convenient (and fast) for simple single-threaded code.

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...
}
查看更多
闭嘴吧你
6楼-- · 2019-01-01 11:47

int* test();

but it would be "more C++" to use vectors:

std::vector< int > test();

EDIT
I'll clarify some point. Since you mentioned C++, I'll go with new[] and delete[] operators, but it's the same with malloc/free.

In the first case, you'll write something like:

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

but it's not a nice idea because your function's client doesn't really know the size of the array you are returning, although the client can safely deallocate it with a call to delete[].

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

A better signature would be this one:

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

And your client code would now be:

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.

Since this is C++, `std::vector< T > is a widely-used solution:

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

Now you don't have to call delete[], since it will be handled by the object, and you can safely iterate it with:

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

which is easier and safer.

查看更多
登录 后发表回答