user3297620
user3297620

Reputation: 103

Why can't C functions return an array type?

I am new to C language and am wondering:

Why can't C functions return an array type?

I know that an array name is an address to the first value of the array, and arrays are second-class citizens in C.

Upvotes: 9

Views: 5521

Answers (4)

Richard Chambers
Richard Chambers

Reputation: 17583

Because there is not really any such thing as an array type in C that is similar to the array type of languages such as Java. Modern C compilers will perform consistency checks should the source code provide that information however there are years of C source code that was written before modern compilers and that source code needs to work with modern C compilers.

You can return a pointer to an array if you like and you can use the same syntax with pointers as you use with arrays so far as using subscripts (e.g. *a is the same as a[0] for some pointer a).

Or you can return a struct which you could then use to provide some of the capabilities of an array type seen in a language such as Java.

So you could do something like the following.

typedef  struct {
    things *array;
    int    iCount;
} MyArrayType;

Then you could do something like allocate an array and then return it.

MyArrayType myFuncIntArray (int iCount)
{
    MyArrayType ret = {0};

    ret.array = malloc (iCount * sizeof(things));
    ret.iCount = iCount;

    return ret;
}

Naturally you could change the function to create an array of whatever type you want to create. Unfortunately you would also be responsible for freeing the memory after you are done with it since garbage collection is not a core offering of C though there is the Boehm-Demers-Weiser garbage collector for C and C++.

C does it that way because the brilliant guys who designed it made it that way and the C Standards Committee has not changed it in some 40 years.

Original design goals for C were simplicity and conciseness of code and extensibility of the core language through function libraries in order to keep the C compiler simple and small while providing flexibility to the programmer. High performance of the resulting machine code was also a design goal. However these design goals also placed a large responsibility of program correctness and performance on the programmer.

Upvotes: 1

Barmar
Barmar

Reputation: 780974

Based on The Development of the C Language, it looks like the real reason is mostly related to the evolution of C from B and BCPL. B didn't have array variables, all it had were pointers. It didn't have structures, either. When structures were added to C, and they were allowed to contain array members, he needed a way to handle these enclosed arrays similarly to the way the B-style arrays were handled, and the solution was to have arrays convert to pointers whenever they're used in expressions. Here's the section of the paper explaining this.

Problems became evident when I tried to extend the type notation, especially to add structured (record) types. Structures, it seemed, should map in an intuitive way onto memory in the machine, but in a structure containing an array, there was no good place to stash the pointer containing the base of the array, nor any convenient way to arrange that it be initialized. For example, the directory entries of early Unix systems might be described in C as

struct {
     int inumber;
     char name[14];
  };

I wanted the structure not merely to characterize an abstract object but also to describe a collection of bits that might be read from a directory. Where could the compiler hide the pointer to name that the semantics demanded? Even if structures were thought of more abstractly, and the space for pointers could be hidden somehow, how could I handle the technical problem of properly initializing these pointers when allocating a complicated object, perhaps one that specified structures containing arrays containing structures to arbitrary depth?

The solution constituted the crucial jump in the evolutionary chain between typeless BCPL and typed C. It eliminated the materialization of the pointer in storage, and instead caused the creation of the pointer when the array name is mentioned in an expression. The rule, which survives in today’s C, is that values of array type are converted, when they appear in expressions, into pointers to the first of the objects making up the array.

This isn't specific to passing arrays to and from functions, it applies any time an array is used in an expression (except when it's the argument of the & operator).

Note also that this design allows array variables and memory allocated dynamically with malloc() to be treated equivalently when passed to function.

Upvotes: 9

John Bode
John Bode

Reputation: 123458

The reason you cannot return an array from a function is that array types may not be the target of an assignment. You can't write someting like

int arr[N];
arr = foo();

Array expressions lose their "array-ness" when they appear in most contexts. This is the result of a design decision Ritchie made early in C's development. C was derived from an earlier programming language known as B (go figure), which in turn was derived from BCPL. In B, an array object was a pointer to the first element of the array, and array accesses were defined in terms of pointer arithmetic. a[i] was defined as *(a + i); - offset i elements from the address stored in a and dereference the result.

Ritchie kept B's array semantics, but didn't want to set aside the pointer storage those semantics demanded. So he came up with the rule that array expressions would be converted ("decay") to pointer expressions in most circumstances.

This means that arr = foo(); can't work if arr is an array type, because there is no storage set aside for an object named arr separate from the array elements themselves; there's nothing to assign to.

Upvotes: 5

M.M
M.M

Reputation: 141554

You answered the question yourself already: arrays are second-class citizens.

C returns by value. Arrays cannot be passed by value, therefore they cannot be returned.

As to why arrays cannot be passed by value: this was a design decision made by K&R when they were first designing the language, and it's too late to change it now because all the existing C code would break.

Upvotes: 10

Related Questions