I know that in C we cannot return an array from a function, but a pointer to an array. But I want to know what is the special thing about structs that makes them return-able by functions even though they may contain arrays.

Why is the struct wrapping makes the following program valid?

#include <stdio.h>

struct data {
    char buf[256];
};

struct data Foo(const char *buf);

int main(void)
{
    struct data obj;
    obj = Foo("This is a sentence.");
    printf("%s\n", obj.buf);
    return 0;
}

struct data Foo(const char *buf)
{
    struct data X;
    strcpy(X.buf, buf);
    return X;
}

A better way of asking the same question would be "what is special about arrays", for it is the arrays that have special handling attached to them, not structs.

The behavior of passing and returning arrays by pointer traces back to the original implementation of C. Arrays "decay" to pointers, causing a good deal of confusion, especially among people new to the language. Structs, on the other hand, behave just like built-in types, such as ints, doubles, etc. This includes any arrays embedded in the struct, except for flexible array members, which are not copied.


First of all, to quote C11, chapter §6.8.6.4, return statement, (emphasis mine)

If a return statement with an expression is executed, the value of the expression is returned to the caller as the value of the function call expression.

Returning a structure variable is possible (and correct), because, the structure value is returned. This is similar to returning any primitive data type (returning int, for example).

On the other hand, if you return an array, by using the return <array_name>, it essentially returns the address of the first element of the arrayNOTE, which becomes invalid in the caller if the array was local to the called functions. So, returning array in that way is not possible.

So, TL;DR, there is nothing special with structs, the speciality is in arrays.


NOTE:

Quoting C11 again, chapter §6.3.2.1, (my emphasis)

Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. [...]