3

Let's say I have

struct my_type_t {
    int x;
    int y;
    int z;
};

struct my_array_t {
    struct my_type_t test;
    int otherstuff;
};

int main(void) {
    struct my_array_t arrayofstructs[200];
    somefunction(arrayofstructs);

    return 0;
}

void somefunction(struct my_array_t *arrayofstructs, somevariable) {
    for (int i; i < 200; i++) {
        //Do stuff to 
        arrayofstructs->test[i].somevariable;
    }
}

How can I pass in somevariable to tell the function to process that member (x, y, or z) of the array of structs?

Thanks!

4 Answers4

1

Fact One: You should pass, arrayofstructs and not &arraystructs.

A way to deal with your problem would be like this:

void someFn(data_type *var , int somevar) {
  ...
  ...
  ...
  switch(somevar) {

  case <some_value>:
  some_task;
  break;

  ...
  ...
  ...
  } //End switch

  }

i.e., you pass an identifier related to each of the member and use selective structure to perform certain tasks according to the input identifier.

For a simple example, somevar can be integer, and you must know what the value in the integer corresponds to.

EDIT

Or you can do the following

struct mystr{
  int mem[3];
}

void someFn(struct mystr a, int somevar){ 

  //now access those with a[i].mem[somevar]
}

That helps clearing the redundancy :)

cipher
  • 2,414
  • 4
  • 30
  • 54
1

The other answers using switch case are probably cleaner but if some hackiness is okay you can use something like this:

#define GET_STRUCT_OFFSET(st, m) ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))

(see Why does this implementation of offsetof() work?)

To access a member of the struct you would do something like:

int main(void) {
    struct my_array_t arrayofstructs[200];
    somefunction(arrayofstructs, GET_STRUCT_OFFSET(struct my_type_t, x));

   return 0;
}

void somefunction(struct my_array_t *arrayofstructs, int offset)
{
    for (int i; i < 200; i++) {
        //Do stuff to 
        (((void*)&arrayofstructs[i].test) + offset);
    }
}

Again pretty hacky but it does infact work heres a simple test: http://ideone.com/zwvTY1

Edit:

In <stddef.h> there is an offsetof macro which accomplishes the same thing code using that: http://ideone.com/9aDo2c

Community
  • 1
  • 1
Robert Prior
  • 508
  • 4
  • 14
  • I thought about using address offset, but this code needs to be portable between machines of differing structure alignments and I thought using this technique would cause problems. – user2272403 Apr 15 '13 at 18:52
  • @user2272403 See edit I just realized there is a standard version. – Robert Prior Apr 15 '13 at 18:59
  • I like this one too. It does require one extra addition per iteration of the loop, though, but everything comes with a price. – user2272403 Apr 15 '13 at 19:16
  • Well to be fair the macro will take a bit extra as would a switch case. Though I doubt either would be a bottle neck compared to whatever the "Do stuff" is. – Robert Prior Apr 15 '13 at 19:19
0
enum FieldTypes
{
   FIELD_X,
   FIELD_Y,
   FIELD_Z
};

int main(void)
{
    struct my_array_t arrayofstructs[200];
    somefunction(arrayofstructs,FIELD_X);

    return 0;
}

void somefunction(struct my_array_t *arrayofstructs, FieldTypes somevariable) 
{
    switch( somevariable )
    {
        case FIELD_X:

           for (int i; i < 200; i++) 
           {
               //Do stuff to arrayofstructs->test[i].x; 
           }
           break;

        case FIELD_Y:

           for (int i; i < 200; i++) 
           {
               //Do stuff to arrayofstructs->test[i].y; 
           }
           break;

        case FIELD_Z:

           for (int i; i < 200; i++) 
           {
               //Do stuff to arrayofstructs->test[i].z;
           }
           break;
    }
}

If the intent is to always do the same operation, but just do it on a different element of the structure based on the passed value, then you can do that like this...

void somefunction(struct my_array_t *arrayofstructs, FieldTypes somevariable) 
{
    for (int i; i < 200; i++) 
    {
        int* workingValue;

        switch( somevariable )
        {
            case FIELD_X: workingValue = &arrayofstructs->test[i].x;  break;
            case FIELD_Y: workingValue = &arrayofstructs->test[i].y;  break;
            case FIELD_Z: workingValue = &arrayofstructs->test[i].z;  break;
        }

        // do stuff to *workingValue -- no redundant code here
    }
}
K Scott Piel
  • 4,320
  • 14
  • 19
0

Just use some distinct values to allow your function to distinguish between them. You could use an enum, some #defines or maybe a char, like this:

void somefunction(struct my_array_t *arrayofstructs, char whichVar) {
    for (int i; i < 200; i++) {
        //Do stuff to 
        switch(whichVar){
            case 'x': arrayofstructs->test[i].x; break;
            case 'y': arrayofstructs->test[i].y; break;
            case 'z': arrayofstructs->test[i].z; break;
        }
    }
}

Note that using #defines or enums is generally considered better practice as you can give your values meaningful names. The char usage here is just an example.

See also What is a magic number, and why is it bad?

Community
  • 1
  • 1
Kninnug
  • 7,992
  • 1
  • 30
  • 42