为什么C需要数组才有指针?

7 c arrays types pointers

如果我们可以使用指针并malloc创建和使用数组,为什么数组类型存在于C中?如果我们可以使用指针而不是没有必要吗?

pmg*_*pmg 9

数组比动态内存分配更快.

数组在"编译时"被"分配",而malloc在运行时分配.分配需要时间.

此外,C并未强制要求,malloc()并且朋友可以独立实施.


编辑

数组示例

#define DECK_SIZE 52
int main(void) {
    int deck[DECK_SIZE];
    play(deck, DECK_SIZE);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

例子 malloc()

int main(void) {
    size_t len = 52;
    int *deck = malloc(len * sizeof *deck);
    if (deck) {
        play(deck, len);
    }
    free(deck);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在数组版本中,阵列的空间deck由编译器在创建程序时保留(但是,当然,内存仅在程序运行时保留/占用),在malloc()版本中,deck数组的空间具有在每次运行程序时都要求.

数组永远不会改变大小,malloc内存可以在需要时增长.

如果您只需要固定数量的元素,请使用数组(在您的实现范围内).如果您需要在程序运行期间可以增长或缩小的内存,请使用malloc()和朋友.

  • 两者的分配都在运行时发生.区别在于C允许您在运行时为一个而不是另一个提供大小. (2认同)
  • @AraK,我认为通过在运行时分配,他意味着软件必须从OS请求内存(调用`malloc`),而不是只调整堆栈指针(因此"分配"在"编译时间"). (2认同)

Art*_*ius 7

这不是一个糟糕的问题.实际上,早期的C没有数组类型.

全局和静态数组在编译时分配(非常快).其他数组在运行时(快速)分配在堆栈上.使用malloc分配内存(用于数组或其他方式)要慢得多.在重新分配中可以看到类似的事情:动态分配的内存释放速度较慢.

速度不是唯一的问题.数组类型在超出范围时会自动释放,因此不会被错误地"泄露".你不必担心意外地释放两次,等等.它们还使静态分析工具更容易检测错误.

您可能会争辩说有一个函数_alloca()可以让您从堆栈中分配内存.是的,没有技术原因需要数组_alloca().但是,我认为数组使用起来更方便.此外,编译器更容易优化数组的使用,而不是具有_alloca()返回值的指针,因为很明显堆栈分配的数组与堆栈指针的偏移是什么,而如果_alloca()被视为黑盒子函数调用时,编译器无法提前告诉此值.

编辑,因为tsubasa要求提供有关此分配如何发生的更多详细信息:

在x86体系结构中,ebp寄存器通常引用当前函数的堆栈帧,并用于引用堆栈分配的变量.例如,您可能int位于at处,[ebp - 8]并且char数组从[ebp - 24]to 延伸[ebp - 9].也许堆栈上有更多的变量和数组.(编译器决定如何在编译时使用堆栈帧.C99编译器允许将可变大小的数组分配给堆栈,这只是在运行时进行一些工作的问题.)

在x86代码中,指针偏移(例如[ebp - 16])可以在单个指令中表示.很有效率.

现在,重要的一点是,当前上下文中的所有堆栈分配的变量和数组都是通过来自单个寄存器的偏移来检索的.如果你调用malloc,那么(正如我所说)实际为你找到一些内存会有一些处理开销.而且,malloc为您提供了一个新的内存地址.假设它存储在ebx寄存器中.您不能再使用偏移量ebp,因为您无法分辨编译时的偏移量.所以你基本上"浪费"了一个额外的寄存器,如果你使用普通的数组而不需要它.如果你使用malloc更多的数组,你会有更多"不可预测的"指针值来放大这个问题.

  • @Ed Swangren:虽然常见的编码实践是在释放它们之后将指针变量设置为NULL:A)不是每个人都这样做,而B)在数据结构中可以有多个指针指向同一个东西,这不能阻止问题 (2认同)