tags:

views:

112

answers:

4

I understand that in order to return a string from a function I have to return a pointer. What I don't understand is why a char array is treated somewhat different from, say, integer, and gets destroyed when you exit the function. That's probably because I come from a high-level languages world, but this seems to be equally valid to me:

int x = 1;
return x;

char x[] = "hello";
return x;
+3  A: 

An integer is a primitive type, so it's value is returned as such. However, in C, a string is not a primitive type, which is why you declare it as an array of characters. And when you return an array, you are actually returning a pointer to the original array, so it is a kind of return-by-reference, if you will. But as you can see, the pointer to char x[] is invalid once you exit the function.

casablanca
So only primitive types in C may be returned from functions without using pointers, is that correct?
snitko
no, as caf points you can also return a struct. the point is that you're returning a pointer to something else (your array), and that something else happens to be in a volatile space (the function's stack frame). once it's gone, the pointer is no longer valid.
Javier
@snitko: Nope, aggregate types may be returned from functions too. It's only array types that can't be directly returned.
caf
+1  A: 

That char array is allocated within the scope of the function (rather than dynamically allocated eg by malloc()), so it will be unavailable outside of that scope.

Two ways around it:

  1. Declare that char array to be static
  2. Allocate the buffer in the calling function, passing it as an argument, then this function just fills it.
thomasrutter
@thomasrutter: If the character array is static, you better hope it is only being used inside this one function (that is, the function never returns references to the static character array to the caller of the function) unless you want tons of fun multithreading issues and "hey why did my string just change for no apparent reason?" type problems. Even if it is just used inside the function, having it as a static can still cause multithreading issues.
George
Yep that is all true. Don't do this if you run the function more than once, especially when multithreading. PS I got the idea from http://vijayinterviewquestions.blogspot.com/2007/07/write-c-code-to-return-string-from.html
thomasrutter
+2  A: 

Please see this detailed answer I have written about this. Not alone that, in C, variables that are created within the scope of functions are using an automatic stack heap where the variables will resides in and when the function returns, that heap is destroyed, this is where the usage of local variables especially of type string i.e. char [] or a pointer to string must be allocated on the heap outside of the function scope otherwise garbage will be returned. The workaround on that is to use a static buffer or use malloc.

tommieb75
@tom, I find that answer misleading with regard to automatic (stack) variables. "the compiler and linker gave the symbol name a memory address of 0x1234." seems to imply that automatic arrays have a compile-time fixed address. Clearly that's not correct; they are allocated on the stack. If it were fixed at compile time, recursion would be impossible. Static arrays do have fixed addresses.
Matthew Flaschen
@Matthew: Not to be pedantic, its just an example, its my way of explaining to a complete beginner..the differences in the nuances of arrays and pointers.... :)
tommieb75
+8  A: 

The reason is both simple, yet subtle: C functions cannot be declared to return arrays.

When you return a pointer, like this:

char *foo(void)
{
    char x[] = "hello";
    return x;
}

The return x; is not actually returning x. It is returning a pointer to the first element of x1 - it is exactly the same as saying:

return &x[0];

It should be more clear why this isn't correct - it is exactly analagous to this:

int *foo(void)
{
    int x = 100;
    return &x;
}

It is, however, possible to return structures from functions - so you can return an array as long as it wrapped inside a struct. The following is quite OK:

struct xyzzy {
    char x[10];
};

struct xyzzy foo(void)
{
    struct xyzzy x = { "hello" };
    return x;
}


1. This is a consequence of a special case rule for array types. In an expression, if an array isn't the subject of either the unary & or sizeof operators, it evaluates to a pointer to its first element. Trying to pin down actual an array in C is a bit like trying to catch fog in your hands - it just disappears, replaced by a pointer.

caf
I've understood your answer, but I'm a little confused. In code block #1 is C automatically returns a pointer (e.g converts "return x;" to "return " because we declared the function as the one that returns a pointer (using *), or is the code just not valid?
snitko
@snitko: C treats it the same as `return
caf
There is no "automatic return", try to return a boolean and it will blow up. The reason that it works is that `char x[]` is an "array" therefore it's a pointer(!). You could also use `char *x = "hello"` which has is exactly the same as `char x[]`, the `[]` is just syntactic sugar. Arrays in C a merely pointers to the start position of the "array" in memory.
Ivo Wetzel
@Ivo Wetzel: No, arrays are *not* the same thing as pointers. This is a common, yet incorrect understanding. In particular, `char *x = "hello";` declares `x` as a pointer, whereas `char x[] = "hello";` declares `x` as an array of 6 chars (try printing `sizeof x` in both cases!).
caf
@Ivo Wetzel: No, arrays aren't pointers, as explained in caf's footnote. Also, `char *x = "hello"` is not at all like `char x[] = "hello"`, and the first way actually would work fine since it would be returning a pointer to a string literal.
jamesdlin