views:

89

answers:

3

I'm currently self-studying C for mastering an university project. In that project we have several signatures given that we need to implement for solving our task. After several hours of trying to make some progress, I must admit that I'm totally confused about the return types of functions. I will show you some code:

This is a structure given to represent numbers in the power to the basis 32.

#include <stdio.h>
#include <stdlib.h>

typedef unsigned int uint32;
typedef struct 
{
  int n;
  uint32* words;
}
foo;

We need to implement some functions like the one with the following signature:

foo add(foo* a, foo* b);

As can you see, the function takes two pointers to the structure as parameters, and returns the value of a structure, and not the pointer to it. That means that I have to locally create an instance of foo and return it.

foo add(foo* a, foo* b)
{
  foo result = {1, malloc(sizeof(uint32))};
  // do something with result
  return result;
}

1) Is there anything wrong in this attempt? In my production code I get problems with accessing the value of the returned structure: it seems to they have changed after the structure was returned. Unfortunately I was not able to reproduce that behaviour in a more simple application, which got me even more worried that I'm doing this all wrong. I have also tried to allocate memory with malloc for the variable result, but that only seems to work if I create a pointer to foo, which seems to be no option, because I can't return the pointer.

2) I'm looking for a way to cast (probably not the correct term) the return type back into a pointer. Lets just say I have this code:

   foo* bar1 = malloc(sizeof(foo));
   bar1->n = 1;
   bar1->words = malloc(bar1->n * sizeof(uint32));
   bar1->words[0] = 4294967295;
   foo* bar2 = malloc(sizeof(foo));
   bar2->n = 1;
   bar2->words = malloc(bar2->n * sizeof(uint32));
   bar2->words[0] = 21;
   foo bar3 = add(bar1, bar2);

Works fine. How could I now use the value of bar3 to call the add function again. Like this:

   foo bar4 = add(bar1, bar3);

After also tried various attempts with creating foo* and trying to assign values, but they all failed and I decided to post this question to get some nice answer that helps me understanding C a little bit more.

Thanks for everybody who tries to help, I appreciate that ;)

+2  A: 

You're looking for the address-of operator, &. &foo3 will return a pointer to foo3.

Chuck
+1  A: 
Jesse Dhillon
Edited: I can't use a function signature that returns foo*. I need to return foo. I also tried **foo result = malloc(sizeof(foo));** but that only gives me a compile error stating that I'm using an **invalid initializer**
citronas
I updated my answer, you need to do `foo* result = malloc(...)`, I made a typo. Your function must return a `foo*` to work the way you have described.
Jesse Dhillon
Thanks for you answer. Ok you proved me right of my understanding of the variable scope with memory management on the stack/heap. The thing that is confusing me is that the signature of this function must match the one I posted in my question. (is given by the university) I must return foo and I'm not allowed to return foo*. According to your post and my understanding of memory allocation I can't seem to figure out how to make this work.
citronas
Why must you return a `foo`? Why is the signature fixed? Maybe if you post the real code, it will become clear what the problem is. Another possibility is that instead of returning a `foo`, you can modify one of the `foo`s passed in.
Jesse Dhillon
Because the signature of the method is given in the requirements specification the were given by the university. (I know this tasks is nowhere near any real world application, but unfortunately I have to write the code this way to qualify for the written exams.)
citronas
("foo" is such a lousy struct name, even for an example.) In your called function, declare a `struct foo` but make it `static`. Return that struct to the caller. Then in the caller, make a copy of the returned struct to a locally declared one or allocated one for safekeeping. That "static" declaration keeps the structure from getting torn down when the function exits (among other things). You get your signature, and can safely return a "struct foo" instead of a pointer to "struct foo".
clintp
Won't his code return a copy of the struct?
Lasse V. Karlsen
+3  A: 

1) To access the returned structure you only need to do something like:

 printf("[bar3] n %d words %d\n", bar3.n, *(bar3.words));

2) To pass bar3 again to the function add. You need to pass the mem address of bar3 which can be accessed by using the operator &:

   foo bar4 = add(bar1, &bar3);

or

foo bar3_p = &bar3;
foo bar4 = add(bar1, bar3_p);

If you do it like this you can keep the definition of the function without returning a pointer.

msalvadores
@citronas: And just to make it asolutely clear - there is nothing wrong with the way that you're returning the `struct` in your example `add()` function. In your full program, it's likely that the problem is in the way you allocate the `words` member of the struct.
caf