JasonKeef
JasonKeef

Reputation: 125

question regarding return functions in C

I am a java programmer learning C. Have a question regaring functions. What are the differences between this:

main()
{
    struct person myperson;

    myperson = myfunction();

    return;
}

struct person myfunction()
{
     struct person myPerson;
     myPerson.firstname = "John";
     myPerson.lastname = "Doe";
     return myPerson;
}

VS

main()
{
    struct person *myperson;

    myperson = myfunction();

    return;
}

struct person* myfunction()
{
     struct person *myPerson;
     myPerson = malloc(sizeof(struct person));
     myPerson->firstname = "John";
     myPerson->lastname = "Doe";
     return myPerson;
}

Are these legal in C? And y would 1 choose one over the other. Thanks so much guys!

Upvotes: 10

Views: 398

Answers (10)

Chaka
Chaka

Reputation: 1

First One:

main()
{
    // create a person struct on the stack
    struct person myperson;
    // copy the struct returned by myfunction to myperson.
    myperson = myfunction();
}

struct person myfunction()
{
    // create a person struct on the stack.
    struct person myPerson;
    myPerson.firstname = "John";
    myPerson.lastname = "Doe";
    // return the myPerson struct. After myFunction returns, the memory
    // holding the myPerson struct on the stack will be freed.
    return myPerson;
}

Second one:

main()
{
    // create a pointer to a person struct on the stack
    struct person *myperson;
    // assign the pointer returned by myfunction to myperson
    myperson = myfunction();
}

struct person* myfunction()
{
    // create a pointer to a person struct on the stack
    struct person *myPerson;
    // allocate memory for a person struct in dynamic memory and set myPerson
    // to point to that memory. This memory will remain valid until it's freed by
    // a call to the "free" function. Using malloc is much slower than creating
    // an object on the stack. There is also the added performance cost of
    // freeing the allocated memory at a later stage.
    myPerson = malloc(sizeof(struct person));  
    myPerson->firstname = "John";
    myPerson->lastname = "Doe";
    // return the myPerson pointer
    return myPerson;
}

Upvotes: 0

amit
amit

Reputation: 178461

first code sample:
you create a struct in myfunction() on your stack and return it. then, you create another stack struct, and you copy the first to the second. the first is destroyed. the second will be automatically destroyed when you are out of the scope.
2 structs were actually created.

second code sample:
you create a struct in myfunction(), and then you copy only the address. the struct in main will actually be the same struct.
only one struct is created in here.

both code samples work, but for the later you will have to explicitly free the memory allocated for the struct, to avoid memory leak, but performance should be better since you don't need to copy the struct!

EDIT:
as mentioned by @Mat: this of course neglects the overhead of malloc(), which is not true for small structs.

Upvotes: 7

Klas Lindbäck
Klas Lindbäck

Reputation: 33273

I would actually choose a third way. Let the caller worry about providing storage space (auto or dynamically allocated):

void myfunction(struct person* myPerson)
{
     myPerson->firstname = "John";
     myPerson->lastname = "Doe";
}

The function can be called either with an automatically or dynamically allocated variable:

struct person autoperson;
myfunction(&person);

struct person dynamic_person = malloc(sizeof struct person);
myfunction dynamic_person);

Upvotes: 3

pmg
pmg

Reputation: 108938

In the first code, myPerson is an object of type struct person that is managed (*) by the implementation itself. In the second code, it is an object of type struct person * (a pointer to a struct person). In the second code, the object itself must be managed by the programmer (malloc, realloc, free).

Also, in the first code, the object itself is copied around a few times whereas in the 2nd code "only" the pointer gets copied. Usualy a pointer is much smaller than an object of a struct type.

Use the 2nd approach but remember to free the object.

Even better, create the object in the parent function and pass a pointer to functions: sruct person *myfunction(struct person *data) { /* ... */ }

(*) with object management I mean the time it gets created and deleted and stuff

Upvotes: 0

Kerrek SB
Kerrek SB

Reputation: 477120

I'm not sure if all this talk of "heap" and "stack" is cutting to the core of the language, so let me try something more language-intrinsic.

Your first version uses only automatic allocation, which means that all variables have automatic lifetime. That is, all variables end their life at the end of their enclosing scope: myFunction creates a local variable of type struct person and returns a copy of that variable; the main function declares a local variable of the same type and assigns to it the result of the function call. At the end of each scope, the local variables end as well.

The second version uses dynamic or manual allocation. You explicitly allocate storage for a person variable with the malloc() call, and that storage will remain allocated until someone deallocates is (via free()). Since you never deallocate it, this is in effect a memory leak.

The fundamental difference is one of lifetime and responsibility.

A few pros and cons: Automatic allocation means that responsibility is local, and you generally don't have to worry about anything. However, it comes at the price of having to copy arguments and return values by value, which may be expensive or undesirable. Manual allocation allows you to refer to large amounts of memory via a simple, cheap pointer, and is often the only way to implement certain constructions, but carries the burden of having the author remember who's responsible for which resource.

Upvotes: 4

Armen Tsirunyan
Armen Tsirunyan

Reputation: 133024

The first version allocates the object on the stack and returns a copy of it. The second version creates the object on the heap and returns a pointer to it(this is closest to Java references except that the memory isn't automatically freed). You should not forget to call free() later on the returned pointer.

Btw, your main function is bad. It should be

int main(void)
{    
    ...
    return 0;
}

I suggest that you should read a good C book. This is really basic stuff you're asking.

Upvotes: 7

undur_gongor
undur_gongor

Reputation: 15954

Both are legal, both work.

The 1st version is simpler, you avoid having to deal with memory allocation and releasing.

The 2nd version will perform better for bigger structs because you avoid putting the whole struct on stack for handing it over.

Upvotes: 3

Constantinius
Constantinius

Reputation: 35069

The first option creates a struct on the stack, when returning it, it gets copied to your struct defined in the main() function. Also copied are the fields. For larger structs this can be a costly operation.

The second option allocates dynamic memory, which does not get copied when you return it. You have to free() the pointer to avoid a memory leak.

Of course it depends on your needs, but for more important and long living objects I'd go for the second option. Also I would recommend to write allocation/initialization functions and a corresponding deallocation function. (see below why)

The problem is that the 2 strings you set in myfunction() are invalid outside of the function, as they are also created on the stack. You have to use strdup() or a similar function to make this failsave. Of course, to not let memory leaks slip in you have to free() the strduped pointers, just as with malloc().

Upvotes: 0

sinelaw
sinelaw

Reputation: 16553

The first will allocate a struct person on the stack, and pass a copy of it back, then free the original. The second one will allocate it on the heap and pass a pointer to the location which was allocated, and will not free it.

Upvotes: 1

John Humphreys
John Humphreys

Reputation: 39294

The first one allocates the variables on the stack. The person object from myfunction is copied from the function and returned which is less efficient, but you can't get a memory leak which is good.

The second example returns a pointer (the *) to a person object that is dynamically allocated (with malloc). The person object allocated by malloc will never be destroyed unless you explicitly call free() on it, hwich you haven't - so you have a memory leak.

You need to explicitly free memory in C, it doesn't have garbage-collection like Java.

Upvotes: 0

Related Questions