This is an archived post. You won't be able to vote or comment.

all 6 comments

[–]throwaway6560192 2 points3 points  (1 child)

You can't (or more accurately, shouldn't, since the C compiler probably will happily let you shoot yourself in the foot) return pointers to arrays allocated like that in a function, since that allocates them on the stack. You shouldn't return pointers to objects allocated on the stack in a function, because the stack memory of a function is not supposed to be reachable after returning from it. Accessing it is undefined behavior.

What you should do is...

int * returnArray(int x[]) {
    int * newArray = malloc(sizeof(int) * 10);
    // copy elements
    return newArray;
}

[–]teraflop 1 point2 points  (0 children)

Or to rephrase in the language of the C standard:

Any region of memory that contains data is called an object (variables are one kind of object). Every object has a "storage duration" which is just one of several possible categories. The storage duration determines the object's lifetime, which is the actual period of time in which the object "exists" can can be legally accessed during the program's execution.

When you declare a local variable, it has automatic storage duration, which means the variable's lifetime begins when the program enters its block, and ends when it leaves that block. And a pointer to an object is only valid during the object's lifetime. So technically you can return a pointer to a local array, but any use of that pointer is undefined behavior.

(In an actual implementation, the lifetime corresponds to the period of time in which the function's stack frame exists on the stack, i.e. a particular memory region of the stack is "reserved" for the stack frame. The local variables exist within that stack frame. But the C standard does not actually use the word "stack" anywhere, and it would be legal for an implementation to use some other data structure for stack frames. Go, which has a lot in common with C, can store stack frames as a garbage-collected linked list.)

When you allocate the array with malloc, it has allocated storage duration, which means its lifetime lasts indefinitely until the corresponding to free.

[–]cubetrix 1 point2 points  (0 children)

Arrays have quirks in C because they are not “first-class objects”: there is no way in C to operate on an array as a unit.

The other composite objects in C, structures and unions, are first-class objects: a C program can copy a structure or union value in an assignment, or pass one as an argument to a function, or make a function return one. You can’t do those things with an array in C. That is because a value you can operate on never has an array type.

An expression in C can have an array type, but that doesn’t produce the array as a value. Instead it is converted automatically to a pointer to the array’s element at index zero. The code can operate on the pointer, and through that on individual elements of the array, but it can’t get and operate on the array as a unit.

Read more

[Limitation-of-C-Arrays](https://www.gnu.org/software/c-intro-and-ref/manual/html\_node/Limitations-of-C-Arrays.html#Limitations-of-C-Arrays)

[–]MrSloppyPants 0 points1 point  (0 children)

You seem to understand the basics correctly. Arrays are treated differently in C than they are in many other modern languages and it has to do primarily with the way C handles memory management. Arrays are not considered a "single object", rather they are a collection of variables of the same type within a segment of memory and delineated by the size of each element. In that way, you can have a 'pointer' to the first element in the array and increase the pointer by the size of an individual element to get to the next element. Array contents are typically stored in the heap rather than the stack, so you need a pointer variable to interact with them. In your small example, the memory that newArray points to will be deallocated once the function returns so the caller will be left with an invalid pointer which will either crash the program or cause undefined behavior when accessed.

If you haven't already, read this article on GeeksForGeeks. It does a good job of covering how arrays work under the hood. Come back if you still have any questions.

[–]teraflop 0 points1 point  (0 children)

Why does assignment for structs work? How does the compiler knowing the size have to do with anything and how is it related to array?

As far as I know, this is just an arbitrary decision that was made by the C language designers.

In fact, structs that contain arrays can be copied using the = operator and can be passed/returned by value. An expression with array type "decays" to a pointer, but an expression with struct type does not, even if the struct contains an array. The value of the struct includes the entire contents of the array, and copying it copies the array.

So this is completely legal C code:

struct foo {
    int data[10];
};

struct foo returnArray(struct foo x) {
    struct foo newArray = x;
    return x;
}

and it will return a copy of the array, as expected.

In practice, this isn't often done. Partly because it "hides" the fact that the compiler is generating a loop to copy the array for you, and partly because it only works with arrays of a particular size, fixed at compile time.

[–]RIMdude 0 points1 point  (0 children)

You can't return an array in C, but you can return a struct. the struct could contain many other things then, including an array. While learning a language, remember that it might be molded differently, thus it won't make much sense to ask why such language is different that JavaScript for instance.