2

I understand how to create a struct that can be used to access an array, for example:

#include <stdio.h>

typedef struct {
  int i;
  int j;
  int k;
} MyStruct;

int main()
{
  MyStruct *ms;
  int array[9];
  int i;

  for(i=0;i<9;++i) array[i] = i;

  ms = (MyStruct *)array;

  for(i=0;i<3;++i) printf("%d %d %d %d\n",i,ms[i].i,ms[i].j,ms[i].k);
  return 0;
}

which allows me to access array[0] as ms[1].i and array[1] as ms[1].j etc.. However, how could I do the same thing if I wanted to use an array in the struct that is known at runtime but not at compile time? Something like:

#include <stdio.h>

typedef struct {
  int *myArgs;
} MyStruct;

int main()
{
  MyStruct *ms;
  int array[9];
  int i;

  for(i=0;i<9;++i) array[i] = i;

  ms = (MyStruct *)array;

  for(i=0;i<3;++i) printf("%d %d %d %d\n",i,ms[i].myArgs[0],ms[i].myArgs[1],ms[i].myArgs[2]);
  return 0;
}

which in that example, I would know at runtime that myArgs is length 3. But it's also possible myArgs is length 9, in which case ms should be length 1.

Edit:

I'm storing a solution set for a PDE solver that has a number of fixed-at-compile-time knowns and then an unknown number of extras. For example, my array will have X, Y, Z but then it might have 3 or 5 or 10 more things after that. So, I wanted to provide a structure that gives access to the fields for easy readability later, for example solution.x, solution.y, solution.z, solution.chemicalSpecies[0], solution.chemicalSpecies[1], etc.. The number of species is entirely unknown at compile time.

I'm using an outside library that stores the number of unknowns as an array, and I can get the array back in the form [k][j][i][numUnknowns] and it would be nice to give access like solution[k][j][i].something.

6
  • 1
    Just out of curiosity, why would you want to do this in real code? Commented Dec 12, 2011 at 18:14
  • 1
    None of this is valid; it's all undefined behaviour. Commented Dec 12, 2011 at 18:15
  • The question needs to be clarified. You may want to do something like this if array is a buffer from some sort of external device and you are overlaying an array of structures on top of it. Commented Dec 12, 2011 at 18:24
  • That is correct. The array is coming from another library and I just want to provide a "window" to look at it, if that makes more sense. Commented Dec 12, 2011 at 18:26
  • About @KerrekSB's comment, this code breaks with strict-aliasing. If you compile it with a newer gcc, or with an older gcc with -fstrict-aliasing, you'll probably get bogus results. Commented Dec 12, 2011 at 20:57

3 Answers 3

1

No.

In your first case, the size of your structure is the size of 3 int variables. When you cast the pointer of your array to the pointer of your structure, each 3 int elements will match with the one MyStruct element, what does the magic in your code (that is theoretically non-portable).

In your second case, the size of the structure is the size of 1 pointer to int. You must be aware that pointers have some similarities with arrays regarding usage, but they are not the same thing. Pointers are just one variable with a single value that points to a memory address. The contents of that address can then be used as an array.

In C, structs and arrays sizes are dealt at compile time, so a struct's size cannot change at runtime, thus it will do no good to your purpuse to have a pointer inside your struct, since pointer sizes are also fixed.

Maybe a good solution to you would be to use an abstract data type, like:

typedef struct {
  int m; /* number of lines */
  int n; /* number of columns */
  int *data; /* pointer to the actual data */
} Matrix;

Then you could create ancillary functions for using the struct:

void matrix_new(Matrix *m, int rows, int columns);
int matrix_get(Matrix *m, int i, int j);
void matrix_set(Matrix *m, int i, int j, int value);
void matrix_free(Matix *m);

If that is too clumsy, you could even use a mixed approach (not too "abstract" type):

int matrix_get(Matrix *m, int i, int j)
{
  return m->data[i * m->n + j];
}

int main()
{
  Matrix m;
  int array[9];
  int i;

  for(i=0;i<9;++i) array[i] = i;

  m.m = m.n = 3;
  m.data = array;

  for(i=0;i<3;++i)
    printf("%d %d %d %d\n", i,
                            matrix_get(&m, i, 0),
                            matrix_get(&m, i, 1),
                            matrix_get(&m, i, 2));
  return 0;
}
Sign up to request clarification or add additional context in comments.

Comments

1

Trivially, given array size N and myArgs < N, you will have N/myArgs complete sets of data, with a remainder of N%myArgs items. You could base your array indexing on that fact.

However, this code looks like a maintenence nightmare. What are you trying to accomplish? There is probably a better way.

1 Comment

I'm open to suggestions on a better way to provide easy access. Everybody else I work with comes from a fortran background, so making it easy to understand/use the library is paramount. Even if it means I have more maintenance to do on the back-end.
0

Given your clarification, I would go about the problem as follows. I'd have a struct that had both the fixed x, y, and z, and then a pointer to an array, which you could set to the location of the appropriate point in the solution array. Something like this:

struct MyStruct {
    int x, y, z;
    int *extras;
};

...
int solutions[9];
struct MyStruct ms;
ms.x = solutions[0];
ms.y = solutions[1];
ms.z = solutions[2];
ms.extras = (solutions + 3);
...

That way, you could easily access the fields you need, and extras like:

ms.extras[0]

At least that should work, off the top of my head.

I'd also throw in a num_extras into the struct if I were you, just so you don't run off the end of the array.

Edit: If you were looking to have them be mirrored, you could instead do:

struct MyStruct {
    int *x, *y, *z;
    int *extras;
};

And then have:

...
int solutions[9];
struct MyStruct ms;
ms.x = &solutions[0];
ms.y = &solutions[1];
ms.z = &solutions[2];
ms.extras = (solutions + 3);
...

But that's a lot like what you had before, isn't it?

1 Comment

Wouldn't that duplicate the data though? It would be both in the original array and in the structure, so changes to ms.x would not be reflect in solutions[0] and vice versa after the assignment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.