0

I'm having trouble finding the answer to this problem; I've found similar examples of this online but none that address my problem.

I have a struct for the data for a company, Company, and a second struct for collections of companies, Consortium. The second struct will contain variable length arrays of the first struct, the company data struct. The number of elements of the variable length arrays will depend on the number of companies in a consortium.

I want to dynamically allocate whatever is required but I'm getting a bit lost. These are the structs:

typedef struct {
    char  code[];
    double sharePrice;
    int numShares;
    double totalVal;
    double totalDebts;
} Company;

typedef struct {
    int numCore;
    int numAssoc;
    Company core[];
    Company assoc[];
} Consortium;

There will be a number of core companies, and this number will be the size of the core array in the Consortium struct. Same goes for associate companies.

I came up with this expression but I'm not sure what I'm missing:

Consortium *consort=((Consortium*)malloc((numCore+numAssoc)*(sizeof(Consortium));
Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
Dawson
  • 573
  • 6
  • 24
  • 2
    You can't have *two* variable sized arrays in a structure...how is the poor compiler going to know where the second one starts? Use pointers to arrays instead. – nneonneo Oct 21 '12 at 03:30
  • Say I had 2 pointers to arrays then. How would I dynamically allocate the memory? – Dawson Oct 21 '12 at 03:44
  • I've only now gotten 15 rep, so it was not possible to upvote anything. – Dawson Oct 21 '12 at 04:16

2 Answers2

3

You'll need to use pointers and allocate the arrays separately:

typedef struct
{
    char  *code;
    double sharePrice;
    int numShares;
    double totalVal;
    double totalDebts;
} Company;

typedef struct
{
    int numCore;
    int numAssoc;
    Company *core;
    Company *assoc;
} Consortium;

Consortium *c = malloc(sizeof(*c));    // Error check
c->numCore = 4;
c->core = malloc(sizeof(*c->core) * c->numCore);    // Error check
c->numAssoc = 3;
c->assoc = malloc(sizeof(*c->assoc) * c->numAssoc);    // Error check

for (int i = 0; i < c->numCore; i++)
    c->core[i].code = malloc(32);    // Error check

for (int i = 0; i < c->numAssoc; i++)
    c->assoc[i].code = malloc(32);    // Error check

// Worry about other data member initializations!

It would be simpler and possibly better to modify the Company type to:

typedef struct
{
    char   code[32];
    double sharePrice;
    int    numShares;
    double totalVal;
    double totalDebts;
} Company;

That saves the loops allocating the code elements.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • If you're really confident with your pointer arithmetic and so on, you could do a single memory allocation for everything and then set the pointers to point to the correct locations within the allocated memory. However, there are all sorts of things that could go wrong, and it is much simpler (though a little — emphasis on little — slower) to do it with separate memory allocations. – Jonathan Leffler Oct 21 '12 at 03:58
0

You might consider that you make the Consortium struct a bit simpler. Since you have the counts for each type, core and assoc, you can have just a single array, the first part of which is for core and the second part of which is for assoc.

So your struct would look something like the following source (which has not been compiled and is just jotted down rather than tested so caveat emptor):

typedef struct {
    int numCore;    // number of core companies, first part of m_companies
    int numAssoc;   // number of assoc companies, second part of m_companies
    Company m_companies[1];
} Consortium;

Then you would create your actual data structure by something like:

Consortium *makeConsortium (int numCore, int numAssoc) {
  Consortium *pConsortium = malloc (sizeof(Consortium) + sizeof(Company) * (numCore, numAssoc));
  if (pConsortium) {
      pConsortium->numCore = numCore;
      pConsortium->numAssoc = numAssoc;
  }
  return pConsortium;
}

After this you could fill it in by some functions which indicate success or not:

int addCompanyCore (Consortium *pConsortium, int index, Company *pCompany) {
  int iRetStatus = 0;
  if (pConsortium && index < pConsortium->numCore) {
    pConsortium->m_companies[index] = *pCompany;
    iRetStatus = 1;
  }
  return iRetStatus;
}
int addCompanyAssoc (Consortium *pConsortium, int index, Company *pCompany) {
  int iRetStatus = 0;
  if (pConsortium && index < pConsortium->numAssoc) {
    index += pConsortium->numCore;
    pConsortium->m_companies[index] = *pCompany;
    iRetStatus = 1;
  }
  return iRetStatus;
}

And then you would access them with another set of helper functions.

Company  *getCompanyCore (Consortium *pConsortium, int index) {
  Company *pCompany = 0;
  if (pConsortium && index < pConsortium->numCore) {
    pCompany = pConsortium->m_companies + index;
  }
  return pCompany;
}
Company * getCompanyAssoc (Consortium *pConsortium, int index) {
  Company *pCompany = 0;
  if (pConsortium && index < pConsortium->numAssoc) {
    index += pConsortium->numCore;
    pCompany = pConsortium->m_companies + index;
  }
  return pCompany;
}
Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
  • I'm not sure the benefit of functional access outweighs the complication of combining the two arrays into one. – Jonathan Leffler Oct 21 '12 at 04:03
  • @JonathanLeffler one benefit of combining is that there is not a point at which the Consortium object will be partially created. It will either be all or none because the creation is a single malloc(). By using functional access, you can change the internals to however you would like. For instance if you would like to change to some kind of a dynamic allocation, you could do that. Now if there were to be added additional company types, a change in the functions would be required, probably using command switch of some kind, combining the different types into single getter/setter functions. – Richard Chambers Oct 21 '12 at 11:26