83

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;
}
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • 1
    You could do the same thing with a `union`. What is special about unions? – user253751 Apr 26 '16 at 21:53
  • 21
    You should rather ask why arrays are so weird in C. – CodesInChaos Apr 27 '16 at 15:09
  • when returning a struct, if the struct will not fit into a couple of registers, then a 'hidden' memory his allocated by the compiler, the struct is copied (via memcpy()) to the hidden memory then again copied (via memcpy()) tot he callers' struct variable. That 'hidden' memory is lost to all other functions. The two extra calls to `memcpy()` and the loss of the 'hidden' memory is the main reason that a struct should not be `passed to` nor `returned from` a function. Best policy is to pass a pointer to the struct. – user3629249 Apr 28 '16 at 13:50
  • none of the three answers are addressing the passing of a struct, (rather they only discussing passing arrays), but they do not answer the question. – user3629249 Apr 28 '16 at 13:52
  • 1
    @user3629249 - it is impossible to answer the question because the question is premised on a lack of understanding. The only way to answer the question is to try to explain why the question can't be asked. Imagine if I asked you "Why is Blue the same color as Red?" You would be quick to explain why you can't answer the question. – Hogan May 04 '16 at 17:11
  • @Hogan, Actually, I would discuss the frequency of visible light and how our retinas interpret the different frequencies and how all the colours are just frequencies – user3629249 May 04 '16 at 17:58
  • @user3629249 which is just as much not an answer to my question as dasblinkenlight is not an answer to Sukl's – Hogan May 04 '16 at 18:28

4 Answers4

102

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.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 4
    'causing a good deal of confusion' indeed. 'x' and '&x' being the same value/address is sorta insane. It's not surprising that newbs get indirection wrong:( – Martin James Apr 26 '16 at 18:05
  • 1
    My memory might be cheating on me, but weren't there times when passing `struct`s by value wasn't possible? – alk Apr 26 '16 at 18:46
  • 5
    @alk I think, when structs were first added to the language, there were initially some restrictions on passing them to / returning them from functions, but these were clearly marked as being a deficiency in the compiler that was soon enough corrected, not an indication that there was anything wrong with wanting to pass and return them. – Steve Summit Apr 26 '16 at 18:50
  • 1
    @Steve Summit: Even if it's possible (and it wasn't, per K&R), why would you want to pass/return structs, and not pointers to them? Unless you've never figured out how to work with pointers, in which case why are you using C and not e.g. Java? – jamesqf Apr 27 '16 at 04:35
  • 9
    @jamesqf: `struct Point {short x, y, z;};`. You really want to use pointers to move them around? You're certainly not saving space this way. – Mark VY Apr 27 '16 at 05:18
  • 7
    @jamesqf I'm not sure this deserves a response. If you believe that C is not much more than assembly, if you believe there's never a reason not to use a pointer, I can maybe see how you might think that passing structs is useless. But for the rest of us, who treat C as a high-level language (albeit a low-level one, as HLLs go), and who treat C's type system as general (with the noted exception of the second-class status of arrays), why *wouldn't* we want to pass or return structs? (BTW, IIRC, K&R1 said struct passing was on the way, and it worked in V7 cc by the time the book came out.) – Steve Summit Apr 27 '16 at 11:06
  • 1
    @Steve Summit: A compiler's likely to implement passing a struct by pushing the whole thing on the stack, no? Which takes time proportional to the size of the struct, whereas a pointer is one word, optimizable to a register. Also, now that I think on it, even on a 64-bit machine your Point probably isn't going to save space, since it's going to be padded for alignment. (I see Linux/gcc aligns on 16 byte boundaries unless you use -Os.) – jamesqf May 01 '16 at 07:06
  • @Navin: Why would a struct - or any variable, FTM - invariably be on the stack? It might be if it was declared local to some function in the calling chain, but if it is an extern, or allocated with *alloc? Even if it is, passing by value rather than reference means (compiler optimization aside) putting the values on the calling stack, BY DEFINITION, no? – jamesqf May 14 '16 at 05:17
38

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. [...]

Dan
  • 660
  • 6
  • 15
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • what exactly is OTOH ?! –  Apr 26 '16 at 19:20
  • 1
    @Sukl It's the abbreviation for "on the other hand" :) – Sourav Ghosh Apr 26 '16 at 19:20
  • 1
    @Sukl I think these abbreviations are roughly as old as the Internet itself. They surely were used a lot during the Usenet glory days, and still survive in most forums. Thankfully, even for the unaware, Google can decode them ;-) And there's only a handful which are frequently used today (the most common ones) – chi Apr 27 '16 at 09:19
  • @chi yes.Google is quite brilliant an able to decode them. –  Apr 27 '16 at 09:22
  • 1
    @Sukl: You might find [AcronymFinder](http://acronymfinder.com/OTOH.html) useful for tracking down acronyms. – Jonathan Leffler May 03 '16 at 18:46
11

There isn't anything special about struct types; it's that there's something special about array types that prevents them from being returned from a function directly.

A struct expression is treated like an expression of any other non-array type; it evaluates to the value of the struct. So you can do things like

struct foo { ... };

struct foo func( void )
{
  struct foo someFoo;
  ...
  return someFoo;
}

The expression someFoo evaluates to the value of the struct foo object; the contents of the object are returned from the function (even if those contents contain arrays).

An array expression is treated differently; if it's not the operand of the sizeof or unary & operators, or if it isn't a string literal being used to initialize another array in a declaration, the expression is converted ("decays") from type "array of T" to "pointer to T", and the value of the expression is the address of the first element.

So you cannot return an array by value from a function, because any reference to an array expression is automatically converted to a pointer value.

John Bode
  • 119,563
  • 19
  • 122
  • 198
-5

Structs have data members public by default so it is possible in case of struct to access data in main but not in case of class. So , the struct wrapping is valid.

hoh
  • 1
  • 2
    Have you seen that the question is about C? In C, there is no `public`/`private` distinction, and there are no `class`es. The question is about why a `struct` is needed in C to return the value of an array. – PJTraill May 22 '16 at 15:13