[c] Return a `struct` from a function in C

Today I was teaching a couple of friends how to use C structs. One of them asked if you could return a struct from a function, to which I replied: "No! You'd return pointers to dynamically malloced structs instead."

Coming from someone who primarily does C++, I was expecting not be able to return structs by values. In C++ you can overload the operator = for your objects and makes complete sense to have a function to return your object by value. In C, however, you do not have that option and so it got me thinking what the compiler is actually doing. Consider the following:

struct MyObj{
    double x, y;
};

struct MyObj foo(){
    struct MyObj a;
    
    a.x = 10;
    a.y = 10;
    
    return a;
}        

int main () {

    struct MyObj a;
    
    a = foo();    // This DOES work
    struct b = a; // This does not work
      
    return 0;
}    

I understand why struct b = a; should not work -- you cannot overload operator = for your data type. How is it that a = foo(); compiles fine? Does it mean something other than struct b = a;? Maybe the question to ask is: What exactly does the return statement in conjunction to = sign do?

This question is related to c

The answer is


yes, it is possible we can pass structure and return structure as well. You were right but you actually did not pass the data type which should be like this struct MyObj b = a.

Actually I also came to know when I was trying to find out a better solution to return more than one values for function without using pointer or global variable.

Now below is the example for the same, which calculate the deviation of a student marks about average.

#include<stdio.h>
struct marks{
    int maths;
    int physics;
    int chem;
};

struct marks deviation(struct marks student1 , struct marks student2 );

int main(){

    struct marks student;
    student.maths= 87;
    student.chem = 67;
    student.physics=96;

    struct marks avg;
    avg.maths= 55;
    avg.chem = 45;
    avg.physics=34;
    //struct marks dev;
    struct marks dev= deviation(student, avg );
    printf("%d %d %d" ,dev.maths,dev.chem,dev.physics);

    return 0;
 }

struct marks deviation(struct marks student , struct marks student2 ){
    struct marks dev;

    dev.maths = student.maths-student2.maths;
    dev.chem = student.chem-student2.chem;
    dev.physics = student.physics-student2.physics; 

    return dev;
}

struct var e2 address pushed as arg to callee stack and values gets assigned there. In fact, get() returns e2's address in eax reg. This works like call by reference.


As far as I can remember, the first versions of C only allowed to return a value that could fit into a processor register, which means that you could only return a pointer to a struct. The same restriction applied to function arguments.

More recent versions allow to pass around larger data objects like structs. I think this feature was already common during the eighties or early nineties.

Arrays, however, can still be passed and returned only as pointers.


You can assign structs in C. a = b; is valid syntax.

You simply left off part of the type -- the struct tag -- in your line that doesn't work.


struct emp {
    int id;
    char *name;
};

struct emp get() {
    char *name = "John";

    struct emp e1 = {100, name};

    return (e1);
}

int main() {

    struct emp e2 = get();

    printf("%s\n", e2.name);
}

works fine with newer versions of compilers. Just like id, content of the name gets copied to the assigned structure variable.


When making a call such as a = foo();, the compiler might push the address of the result structure on the stack and passes it as a "hidden" pointer to the foo() function. Effectively, it could become something like:

void foo(MyObj *r) {
    struct MyObj a;
    // ...
    *r = a;
}

foo(&a);

However, the exact implementation of this is dependent on the compiler and/or platform. As Carl Norum notes, if the structure is small enough, it might even be passed back completely in a register.


There is no issue in passing back a struct. It will be passed by value

But, what if the struct contains any member which has a address of a local variable

struct emp {
    int id;
    char *name;
};

struct emp get() {
    char *name = "John";

    struct emp e1 = {100, name};

    return (e1);
}

int main() {

    struct emp e2 = get();

    printf("%s\n", e2.name);
}

Now, here e1.name contains a memory address local to the function get(). Once get() returns, the local address for name would have been freed up. SO, in the caller if we try to access that address, it may cause segmentation fault, as we are trying a freed address. That is bad..

Where as the e1.id will be perfectly valid as its value will be copied to e2.id

So, we should always try to avoid returning local memory addresses of a function.

Anything malloced can be returned as and when wanted


The struct b line doesn't work because it's a syntax error. If you expand it out to include the type it will work just fine

struct MyObj b = a;  // Runs fine

What C is doing here is essentially a memcpy from the source struct to the destination. This is true for both assignment and return of struct values (and really every other value in C)