hoffnung
hoffnung

Reputation: 49

How to return an array of structs

struct zone {
  int a;
  double b;
};
zone *abc() {
  static zone r[10];
  for (int i = 0; i < 10; i++) {
    r[i].a = 2 * i;
    [r[i].b=0.5*i;
    cout << r[i].a << " " << r[i].b << endl;
  }
  return r;
}

int main() {
  zone *PP;
  zone P[10];
  PP = abc();
  for (int i = 0; i < 10; i++) {
    P[i] = (PP + i);

    cout << "work" << P[i].a << endl;
  }
  getch();
}

I need to return an array of structs that is formed in a function called by main. I managed to retrieve an array with a pointer, but with struct it doesn't work.

How do I return a struct array?

Upvotes: 1

Views: 3899

Answers (4)

AnArrayOfFunctions
AnArrayOfFunctions

Reputation: 3744

Well fairly simple - by using another struct to encapsulate the returned array in order to get over 'C' language limitations.

struct zone {
  int a;
  double b;
};

struct zone_array_of_10 {
  zone arr[10];
};

zone_array_of_10 abc() {
  zone_array_of_10 r;
  for (int i = 0; i < 10; i++) {
    r.arr[i].a = 2 * i;
    r.arr[i].b=0.5*i;
    cout << r.arr[i].a << " " << r.arr[i].b << endl;
  }
  return r;
}

int main() {
  zone_array_of_10 PP;

  PP = abc();
  for (int i = 0; i < 10; i++) {

    cout << "work" << PP.arr[i].a << endl;
  }
  getch();
}

It's fact that in 'C' language arrays can't be passed by value. However structures can. So whenever you want to pass the actual content of some array without much hassle - just encapsulate it in a structure.

Upvotes: 1

acwaters
acwaters

Reputation: 586

In C, a function can't take or return an array. This is annoying, and I've never heard a good reason given for it. Anyway, C++ fixed this a long time ago, but it never really caught on, for reasons that will become plain in a moment.

Obligatory "for anything larger than a toy application you should strongly reconsider using naked pointers and/or raw arrays!"

C++ introduced references. They are really just syntactic sugar around pointers, but aren't all variables just syntactic sugar around pointers? In C++, a function can take and/or return a reference to an array. Like so:

int takes (char (&arr)[10])
{
    std::cout << sizeof(arr); // 10
}

int (&returns())[10]
{
    return some_array; // Not a pointer!
}

int (&takes_and_returns (int (&arr)[10])) [10]
{
    return arr;
}

Of course, I don't have to tell you that this is extremely ugly and difficult to read. Modern C++ to the rescue!

template <size_t n, typename T>
using array<n,t> = T[n];

int takes (array<10,int>& arr);

array<10,int>& returns();

array<10,int>& takes_and_returns (array<10,int>& arr);

Note, however, that due to the way new works, it is an ordeal to properly construct and then return a reference to a dynamic array. This is how I did it, but I'm not even sure if this is correct; there might lurk some UB:

int (&returns())[10]
{
    int* x = new int[10];
    return *(int(*)[10]) x;
}

Of course, we can tidy this up a bit:

using arr10 = int[10];

arr10& returns()
{
    int* x = new int[10];
    return *(arr10*) x;
}

And then, at the call site, you'd assign it to a reference like so:

int (&my_array)[10] = returns();
// doing stuff ...
delete[] &my_array;

As you can see, at the end of the day, getting all this to work correctly and to interoperate with existing features is a bit of an ordeal. If you need a function to take or return an array, this is how you do it. But for most purposes, it is better (easier, safer) to use standard library containers.

Upvotes: 0

uilianries
uilianries

Reputation: 3887

You are assigning a value of variable with a pointer:

P[i] = (PP + i);

To get a copy of internal value, you need access struct:

P[i] = PP[i];

Would be like this:

#include <iostream>
using namespace std;

struct zone {
  int a;
  double b;
};

zone *abc() {
   static zone r[10];
   for (int i = 0; i < 10; i++) {
       r[i].a = 2 * i;
       r[i].b=0.5*i;
       cout << r[i].a << " " << r[i].b << endl;
   }
   return r;
}

int main() {
    zone *PP;
    zone P[10];
    PP = abc();
    for (int i = 0; i < 10; i++) {
        P[i] = PP[i];

        cout << "work" << P[i].a << endl;
    }
}

Your struct contains just digits, however, if it contains strings or pointer, you will need make a deep copy.

Upvotes: 1

Dan
Dan

Reputation: 393

A cool feature of C++ is the use of references. The best part of references is that they allow you to pass data in an out of a function without copying the data (you are using the same data inside and pass back out). So if you make a function.

Another method is to use a pointer to a pointer. You can pass a pointer pointer or address of a pointer and malloc within the function.

structure* a;
funct(&a);
printf("%s\n", a[0].printfunction());
printf("%s\n", a[1].printfunction());
...

void funct(structure** a, int size){
*a = (structure*)malloc(sizeof(structure) * size);
(*a)[0] = ...
(*a)[1] = ..
(*a)[ size-1] = ...
}

You can access the array outside of the function. Just be sure to free/delete anything you call with malloc/new. The above code can use new I'm just better with c. You can easily pull the malloc outside of the function and just pass in a pointer to the array.

Upvotes: 0

Related Questions