何时使用数组而不是指针,或反之?

4

我的理解是,指针可以用于动态分配内存,当你需要时(并且知道需要多少内存),而不是静态地使用数组预先分配内存。

我很难确定何时更好地节省计算时间来进行动态分配,以及何时拥有更大的内存占用空间并使用一些计算时间来仅分配所需的内存。

有人能在这个主题上提供一些见解吗?是否有任何通用规则可以帮助?

5个回答

1

一般情况下,当您知道要处理的数据的总大小或者至少是一个最大数据大小时,您应该使用数组。特别是在数据大小变化不是非常大的情况下,例如变化在10到20项之间,最简单的方法可能就是分配20个项目并完成它(除非每个项目都非常大)。

如果您事先对数据的大小没有太多了解,或者(重要的可能性)可能很容易处理过多的数据无法计划放在堆栈上,则动态分配将变得更加有用。动态分配的主要弱点是,如果您需要知道大小,则需要自己跟踪它,并且您需要确保在完成后释放内存。许多C语言中(尤其是困难和令人讨厌的)问题归结为在释放内存后继续使用内存,或忘记在完成后释放内存。


1

在以下情况下应使用动态分配的内存:

  • 在编译时不知道需要多少内存
  • 运行时内存量变化
  • 需要大量内存

在以下情况下应使用静态分配的内存:

  • 在编译时知道大小
  • 所需内存量较低

使用动态分配的内存需要使用系统调用,这是当您的程序向操作系统请求某些内容时发生的。您会面临速度惩罚,因为该进程可能会失去分配给另一个进程的“处理时间”。操作系统需要执行许多任务才能完成调用。对于请求内存进行系统调用比仅写入存储在进程堆栈中的数组要复杂得多。


有没有一个好的方法来定义“所需内存量低”的“低”?我不知道这个阈值在哪里。 - Mark
这真正触及了我试图提出的问题的核心(但可能表达得不好)。然而,我仍然对您认为的低内存阈值感兴趣。 - Mark
@Mark:栈有一个限制,如果你可以在那里“存储”所需的所有内存,那可能会很“低”。但要注意,所有函数都使用栈,因此如果许多函数使用内存,您可能会遇到堆栈溢出。有时更安全地使用动态内存。这完全取决于程序需要多少内存以及运行在哪个操作系统上。没有大或小的规则,这只是经验问题。 - anizzomc

0

数组只是一段连续的内存块。当你声明一个数组时,你就拥有了一个指针。

int foo[5];

foo(没有索引)是指向该数组中第一个元素的指针。

foo[0] = 1;
*foo = 1;

它们做相同的事情,如下所示:

foo[1] = 2;
*(foo + 1) = 2;

当你使用int foo[5];创建一个数组时,你是在堆栈上创建的。这只限于当前函数,在从函数返回后就不再有效了。如果你使用malloc()函数分配内存,那么你所创建的数组就在堆上(并且有一个指向它的指针)。
int *foo = malloc(sizeof(int) * 5);
foo[0] = 1;
*foo = 1;

你需要自己管理内存,并且在使用完后使用 free() 释放它:
free(foo);

0
尽管这个问题有一个被接受的答案,让我谈谈稍微不同的事情。在 C 语言中,有时可以使用大小在运行时确定的数组。例如:
void foo (int a[], int n) {
    int buf[n];
    /* do something with buf[] */
}

这种类型的数组在堆栈中分配,并且大小可变。与使用malloc的区别在于,您不必手动释放内存;当函数调用结束时,内存会被自动释放。当然,这也意味着您可能无法返回数组的地址。

0

当你的数据是动态的,或者你需要从程序的不同区域传递数据时,你可以使用动态容器。

1 - 动态数据 比如说你有一个邻居列表。他们在你的街上建了一座新房子,你需要把一个人添加到列表中,但你只为15个邻居分配了足够的空间。这种动态内存可以让你增加容器的大小。实际上并不是这样工作的。它实际上是找到一个必要大小的新内存块,然后将旧容器复制过去。

再举个例子。假设你正在编写一个跟踪通讯录的程序。其中一个用户有十个联系人。另一个用户是一家公司,有五万名员工都需要存储在这个通讯录中。你不想为只有十个联系人的用户分配50000个空间,所以你只分配需要的空间。

2 - 传递数据 当你分配静态数据时,它被放在堆栈上,超出作用域后就无法访问。所以如果你调用某个生成数组的函数,并将数组的内存地址传递回给调用者,你会得到一个运行时错误。这是因为在该函数退出后,数组就超出了作用域,因此从堆栈中弹出。

然而,如果您动态分配它,它将进入堆栈,并且在您释放它或程序退出之前不会被释放。因此,您可以仅保留指向数组开头的指针,并在整个程序中使用它,而无需担心它超出范围,直到您想要释放它为止。


谢谢arasmussen,我很感激你的见解。我的兴趣真正在于你的第二个例子,即地址簿。从数组转换为指针的阈值在哪里?如果员工的最大数量是100而不是50000怎么办?这只是一个判断吗还是有任何规则? - Mark
我总是会动态地处理它。硬编码某个值是没有意义的,因为这样会限制你的程序,并且浪费不必要的内存。此时,内存的唯一限制是他们的硬件/设置,而不是你的程序。此外,我只有在数组始终具有完全相同的大小时才使用静态值。因此,如果您要存储3D坐标的位置,则始终有三个坐标,因此您将使用具有3个值的数组。没有必要使其动态化。 - Andrew Rasmussen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接