为什么 C 函数不能 return 数组类型?

Why can't C functions return an array type?

初学C语言,疑惑:

为什么 C 函数不能 return 数组类型?

我知道数组名是数组第一个值的地址,数组是 C 中的第二个 class 公民。

因为C语言中并没有真正类似于Java等语言的数组类型的数组类型。如果源代码提供该信息,现代 C 编译器将执行一致性检查,但是在现代编译器之前编写了多年的 C 源代码,并且源代码需要与现代 C 编译器一起使用。

如果你愿意,你可以 return 一个指向数组的指针,你可以使用与数组相同的指针语法,只要使用下标(例如 *aa[0] 对于某些指针 a)。

或者您可以 return 一个 struct 然后您可以使用它来提供数组类型的一些功能,例如 Java.

因此您可以执行以下操作。

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

然后你可以做一些事情,比如分配一个数组,然后 return 它。

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

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

    return ret;
}

当然,您可以更改函数以创建您想要创建的任何类型的数组。不幸的是,您还需要负责在完成后释放内存,因为垃圾收集不是 C 的核心产品,尽管有 Boehm-Demers-Weiser garbage collector for C and C++.

C 之所以这样做,是因为设计它的聪明人就是这样做的,而且 C 标准委员会已经有 40 年没有改变它了。

C 的最初设计目标是通过函数库实现代码的简单性和简洁性以及核心语言的可扩展性,以便在为程序员提供灵活性的同时保持 C 编译器的简单和小型化。生成的机器代码的高性能也是一个设计目标。然而,这些设计目标也让程序员承担了程序正确性和性能的重大责任。

你自己已经回答了这个问题:数组是二等class公民。

C returns 按值。数组不能按值传递,因此不能返回。

至于为什么数组不能按值传递:这是 K&R 在他们最初设计语言时做出的设计决定,现在更改它为时已晚,因为所有现有的 C 代码都会中断。

根据The Development of the C Language,看起来真正的原因主要与C从B和BCPL的演变有关。 B 没有数组变量,它只有指针。它也没有结构。当结构被添加到 C 中,并且允许它们包含数组成员时,他需要一种类似于处理 B 样式数组的方式来处理这些封闭数组,解决方案是让数组在它们存在时转换为指针。 re 用于表达式中。这是解释这一点的论文部分。

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.

这并不特定于将数组传入和传出函数,它适用于表达式中使用数组的任何时候(除非它是 & 运算符的参数)。

另请注意,此设计允许使用 malloc() 动态分配的数组变量和内存在传递给函数时被同等对待。

不能从函数中 return 数组的原因是数组类型可能不是赋值的目标。你不能写像

这样的东西
int arr[N];
arr = foo();

数组表达式在大多数情况下出现时会失去其 "array-ness"。这是 Ritchie 在 C 的开发早期做出的设计决定的结果。 C 派生自一种称为 B(见图)的早期编程语言,而 B 又派生自 BCPL。在 B 中,数组对象 指向数组第一个元素的指针,数组访问是根据指针算法定义的。 a[i] 被定义为 *(a + i); - 从 a 中存储的地址偏移 i elements 并取消引用结果。

Ritchie 保留了 B 的数组语义,但不想保留这些语义所需的指针存储。所以他想出了在大多数情况下数组表达式将被转换 ("decay") 为指针表达式的规则。

这意味着如果 arr 是数组类型,arr = foo(); 将无法工作,因为没有为名为 arr 的对象预留与数组元素本身分开的存储空间;没有任何东西可以分配给