Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如果C有指针,为什么它需要数组?_C_Arrays_Types_Pointers - Fatal编程技术网

如果C有指针,为什么它需要数组?

如果C有指针,为什么它需要数组?,c,arrays,types,pointers,C,Arrays,Types,Pointers,如果我们可以使用指针和malloc来创建和使用数组,为什么数组类型存在于C中?如果我们可以使用指针,这不是没有必要的吗?数组比动态内存分配更快 数组在“编译时”进行“分配”,而malloc在运行时进行分配。分配需要时间 另外,C并不要求在独立的实现中提供malloc()和friends 编辑 数组示例 #define DECK_SIZE 52 int main(void) { int deck[DECK_SIZE]; play(deck, DECK_SIZE); ret

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

数组比动态内存分配更快

数组在“编译时”进行“分配”,而malloc在运行时进行分配。分配需要时间

另外,C并不要求在独立的实现中提供
malloc()
和friends


编辑

数组示例

#define DECK_SIZE 52
int main(void) {
    int deck[DECK_SIZE];
    play(deck, DECK_SIZE);
    return 0;
}
malloc()的示例

在数组版本中,编译器在创建程序时保留了
deck
数组的空间(当然,内存仅在程序运行时保留/占用),在
malloc()
版本中,每次运行程序时都必须请求
deck
数组的空间

阵列永远不会改变大小,malloc的内存可以在需要时增长

如果只需要固定数量的元素,请使用数组(在实现的限制范围内)。
如果您需要在程序运行期间可以增加或减少的内存,请使用
malloc()
和friends。

数组有其用途,并且应该在您可以的时候使用,因为静态分配将有助于使程序更稳定,并且由于需要确保不会发生内存泄漏,因此有时是必要的

它们的存在是因为某些需求需要它们

在诸如BASIC之类的语言中,由于语言构造的原因,您可以使用某些命令,这是已知的。那么,使用malloc创建数组,然后从字符串填充数组有什么好处呢

如果我必须定义操作的名称,为什么不将它们放入数组中呢

C是作为一种通用语言编写的,这意味着它在任何情况下都应该是有用的,因此他们必须确保它具有编写操作系统以及嵌入式系统所需的结构

例如,数组是指定指向malloc开头的快捷方式


但是,想象一下,尝试使用指针操作而不是
vec[x]*vec[y]
来进行矩阵运算。很容易发现错误。

这是个不错的问题。事实上,早期的C没有数组类型

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


速度不是唯一的问题。数组类型在超出范围时会自动解除分配,因此它们不会被错误地“泄漏”。您不必担心意外释放两次某物,以此类推。它们还使静态分析工具更容易检测bug

您可能会争辩说,有一个函数允许您从堆栈中分配内存。是的,没有技术上的理由说明需要在
\u alloca()上使用数组。但是,我认为数组使用起来更方便。此外,编译器优化数组的使用比使用带有
\u alloca()
返回值的指针更容易,因为堆栈分配数组与堆栈指针的偏移量是显而易见的,而如果将
\u alloca()
视为黑盒函数调用,编译器无法提前告知此值

编辑,因为tsubasa要求了解有关如何分配的更多详细信息:

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

在x86代码中,指针偏移量(如
[ebp-16]
)可以在一条指令中表示。效率很高


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

与处理指针相比,数组是一个很好的语法改进。在处理指针时,您可能会在不知不觉中犯各种错误。如果因为使用了错误的字节大小而在内存中移动了太多的空间,该怎么办?

请参见和C。有时动态内存分配只是个坏主意,我使用的C库完全没有malloc()和朋友

您不希望卫星取消对空指针的引用,正如您不希望空中交通管制软件忘记将堆块归零一样

同样重要的是(正如其他人所指出的)理解什么是C的一部分,以及什么将其扩展到各种统一标准(即POSIX)。

关于C历史:

胚胎C

NB存在的时间如此短暂,以至于没有对其进行完整的描述。它提供了int和char类型、它们的数组以及指向它们的指针,以int main(void) { size_t len = 52; int *deck = malloc(len * sizeof *deck); if (deck) { play(deck, len); } free(deck); return 0; }
int i, j;
char c, d;
int iarray[10];
int ipointer[];
char carray[10];
char cpointer[];
struct {
    int   inumber;
    char  name[14];
};