Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding (or doing any other math) every member of two same structs with less code

Tags:

c

struct

So, basically, I want to addify every member of first struct, with every member of second struct, and the structs are of same type. Like this:

struct Foo
{
    int bar1;
    int bar2;
    int bar3;
    int bar4;
    int bar5;
}

Foo AddFoos(Foo foo1, Foo foo2)
{
    Foo foo3;
    foo3.bar1 = foo1.bar1 + foo2.bar1;
    foo3.bar2 = foo1.bar2 + foo2.bar2;
    foo3.bar3 = foo1.bar3 + foo2.bar3;
    foo3.bar4 = foo1.bar4 + foo2.bar4;
    foo3.bar5 = foo1.bar5 + foo2.bar5;
    return foo3;
}

However, when structs keep getting bigger, this way is weird. Is there any way to do it with less lines of code? And preferably without advanced pointer magic?

like image 545
pampeho Avatar asked Dec 21 '22 13:12

pampeho


2 Answers

Use an array instead and a for loop to add the numbers:

struct Foo
{
    int bars[100];
};

for (i=0;i<100;i++)
{
foo3.bars[i]=foo1.bars[i]+foo2.bars[i];
}

You can malloc if the array size is unknown at compile time and change the struct to this and then malloc for all three Foo variables.

struct Foo
    {
        int *bars;
    };
like image 108
P.P Avatar answered Dec 24 '22 02:12

P.P


You want the comfort of named fields (bar1 .. barN) and something like an array you can loop over to automate the operations. First we define the struct (a dense representation of the fields in memory):

struct VectorFields {
    int a;
    int b;
    int c;
};

Then we need to get to know the number of the fields used in that struct:

#define VECTOR_FIELDS_LEN (sizeof(struct VectorFields) / sizeof(int))

(In C++ you could use some template magic foo, here we just use the preprocessor as a simpler variant). Next, we combine the struct VectorFields with an array of int so both match in size, also known as union:

union Vector {
    struct VectorFields fields;
    int raw[VECTOR_FIELD_LEN];
};

(Note: VECTOR_FIELD_LEN must be a known constant value to the compiler, hence the preprocessor thingy before.) You are now able to access the data either by it's name (.fields.a) or by an index (.raw[0]). So, let's write the function which adds the Vector together:

void vector_add(union Vector* result, union Vector* a, union Vector* b) {
    int i;
    for (i = 0; i < TUPLE_LEN; i++) {
        result->raw[i] = a->raw[i] + b->raw[i];
    }
}

You might use it like this then:

#include <stdio.h>
int main() {
    union Vector a = { .fields = { 1, 2, 3 } };
    union Vector b = { .fields = { 4, 5, 6 } };
    union Vector sum;

    vector_add(&sum, &a, &b);

    printf("%d %d %d\n", sum.fields.a, sum.fields.b, sum.fields.c);
    return 0;
}
like image 40
akira Avatar answered Dec 24 '22 00:12

akira