tags:

views:

147

answers:

4
+3  Q: 

C struct arrays

I have a C (not C++) struct that goes like this

typedef struct mystruct{
float a,b;
int x, y;
} mystruct;

Then in a function I collect data like this:

mystruct List[MAX];
ListNumber = 0;

for(i = 0; i < MAX; i++)
{
 if(conditions_meet)
 {
  List[ListNumber].a = masterlist[i].a;

...etc

ListNumber++;
 }
}

then I send the array to a function

 DoStuff(static int max, mystruct array[max]){
  Stuff
 }

This works, but when I try to do it like this....

mystruct setter(int i)
{
mystruct TEMP;
TEMP.a = masterlist[i].a;
 //......etc
return TEMP;
}


mystruct List[MAX];
ListNumber = 0;

for(i = 0; i < MAX; i++)
{
 if(conditions_meet)
 {
  List[ListNumber] = setter(i);
  ListNumber++;
 }
}

It causes a lot of funky errors. Why is this happening? edit: @tommieb75 I can't give much detail, the results do not seem to have a pattern. The list is used as a generalized way to draw stuff to the screen, and having the function instead of the direct setting makes odd problems in rendering -and random-, but produce no compiler errors at all. gdb shows some integers as being larger than an integer, that's the only pattern I find. masterlist is a global array of another struct. The data needs to be converted to the struct in this example. No compiler warnings or errors at all. I can turn in more sensitive warnings maybe, but I always get reported of any general error I can think. I am going to try the selected solution, that should suffice. Anyway similar functions returning structs are used in my code and all work perfectly except for this case with an array of structs.

+1  A: 

what is

mystruct setter(i)
{
mystruct TEMP;
TEMP.a = masterlist[i].a;

'i' has any type?

//If you get errors with uninitialized members in struct that could help http://ideone.com/WRLVG

nilphilus
It's implicitly int.
Potatoswatter
@Potatoswatter arguments too? i remember about return values, but not arguments (anyway you are right)
nilphilus
A: 

The first problem is your definition of setter is not a legal function signature. The parameter i must be given a type

mystruct setter(int i) {
  ...
}

It also uses the variable masterlist which is not defined in the function. This may be legally declared elsewhere as a static. If not though it will need to be accessible to the function in some way

JaredPar
Masterlist is a global. I don't know the proper name in C, though...anyway the code I typed was mostly made on-the-fly, it would have been too large otherwise.
Balkania
Also that wasn't copy-paste of actual code, I just made an example on the fly to remove all surrounding noise...of course the real thing's got that right, or my compiler would complain ;P
Balkania
@Blakania: You're not going to get any useful answers, since your made-up example seems to have left out the actual problem.
caf
The parameter doesn't need to be given a type, it is implicitly `int`.
dreamlax
@caf I don't see how that is the case, I just forgot to add a type -something excusable because I was coding in Lua before typing the post-, the problem is about using a function returning a struct into an array of structs, not about a missing integer declaration that the compiler points out faster than you can say "oops I forgot the type".
Balkania
@Balkania: Because returning a struct by value and copying that return value into an array of structs is fine. So it seems that your problem is due to something that you didn't include in your example - which is why it's usually better to provide a minimal, compilable example that demonstrates the problem. (ie. it's the not the missing `int` that matters, it's that your example isn't demonstrating the real problem).
caf
A: 

The problem is that within the setter function you have a stack allocated variable TEMP which goes out of scope once the function returns... you might be better to allocate the pointer to my_struct on the heap and return the address of it back out to the calling routine...

Edit:

mystruct *setter(int i){
    mystruct *ptr_myStruct;
    ptr_myStruct = malloc(sizeof(mystruct));
    if (ptr_myStruct != NULL){
        ptr_myStruct->a = masterlist[i].a
        // etc...
        return &ptr_myStruct;
    }
    return NULL;
}

mystruct List[MAX];
ListNumber = 0;

for(i = 0; i < MAX; i++)
{
 if(conditions_meet)
 {
  List[ListNumber] = setter(i);
  ListNumber++;
 }
}

That is what is needed to get the values back out once the routine goes out of scope. That is called return-by-reference

tommieb75
It's returned by value.
Potatoswatter
Difference between return-by-value and return-by-reference...which is what I am stating above, by returning back the address to the allocated pointer on the heap that is return by reference.
tommieb75
If it were returning by reference, there would be a problem, but fortunately, C doesn't have that feature. If return by value didn't work, they probably would not have allowed it to compile.
Potatoswatter
@Potatoswatter: change the prototype to this `my_struct* setter(int i){... malloc the pointer to my_struct... return ptr to my_struct` and there you have - return by reference....
tommieb75
@tommieb75: Why `return
Andrew-Dufresne
Your diagnosis of the issue is wrong. `TEMP` is indeed an automatic ("stack") variable, but since the return value makes a *copy* of that value, it's fine.
caf
To clarify - you're returning back the address of the pointer variable for the malloc'd variable once the function goes out of scope....
tommieb75
A: 

For a simple setting a struct member you need a copy from an entire struct-element?

mystruct List[MAX];
ListNumber = 0;

for(i = 0; i < MAX; i++)
{
 if(conditions_meet)
 {
  List[ListNumber].a = masterlist[i].a;
  ListNumber++;
 }
}

If you really need a function, use the destination-memory as parameter like:

void setter(mystruct *dest,const mystruct *src)
{
  dest->a = src->a; 
}
for(i = 0; i < MAX; i++)
{
 if(conditions_meet)
 {
  setter( &List[ListNumber], &masterlist[i] );
  ListNumber++;
 }
}
Yes, the function is to clean up the function a bit, it's a massive eyesore hard to read and alter in a speedy manner. However this seems to be an interesting solution, I am going to test it out.
Balkania