3

我试图理解 C 函数mallocfree. 我知道这已经在 StackOverflow 上讨论了很多。但是,我想我现在有点知道这些功能的作用。我想知道为什么要使用它们。我们来看看这段代码:

int n = 10;
char* array;
array = (char*) malloc(n * sizeof(char));
// Check whether memory could be allocated or not...
// Do whatever with array...
free(array);
array = NULL;

我创建了一个我称之为 char 类型的指针array。然后我曾经malloc找到一块当前未使用且(10 * sizeof(char))字节大的内存。我将该地址转换为类型 char 指针,然后再将其分配给我之前创建的 char 指针。现在我可以使用我的 char 数组了。完成后,我将使用free释放那块内存,因为它不再被使用。

我有一个问题:我为什么不这样做char array[10];?维基百科只有一个小句子可以回答这个问题,不幸的是我不明白这句话:

但是,数组的大小在编译时是固定的。如果希望动态分配一个类似的数组...

我大学的幻灯片同样简洁:

也可以从堆中分配内存。

什么是堆?我知道一种叫做堆的数据结构。:)

但是,我有人可以向我解释在这种情况下使用它是有意义的,mallocfree不是变量的常规声明,那就太好了。:)

4

6 回答 6

4

C 为对象提供了三种不同的可能“存储持续时间”:

  • 自动 - 特定于调用它所在函数的本地存储。如果一个函数被递归调用或从多个线程调用,则可能有多个使用自动存储创建的对象实例。或者可能没有实例(如果/当没有调用函数时)。

  • 静态 - 在运行程序的整个持续时间内,仅在一个实例中存在的存储。

  • 已分配(动态) - 由 创建malloc,并一直持续到free被调用以释放它或程序终止。分配的存储是唯一可以创建任意大或任意多个对象的存储类型,即使函数返回也可以保留这些对象。这是malloc有用的。

于 2013-11-11T19:09:43.267 回答
1

关于你的问题: 为什么我不只做 char array[10];?. 你可以,而且大多数时候,这将是完全足够的。但是,如果您想做类似但更大的事情怎么办?或者,如果您的数据大小在执行期间需要更改怎么办?这些是指向使用动态分配的内存(calloc()malloc())的一些情况。

了解一下如何/何时使用堆栈和堆会很好:当您使用malloc()or calloc()时,它使用堆中的内存,其中自动/静态变量在堆栈上分配内存,并在您离开范围时被释放该变量,即声明它的函数或块。

当您需要的数据大小直到运行时才知道时,使用 malloc 和 calloc 变得非常有用。确定大小后,您可以轻松调用其中之一以将内存分配到堆上,然后在完成后使用free()

关于什么是堆?有一个关于该主题的很好的讨论here(略有不同的主题,但很好的讨论)

作为回应但是,我有人可以向我解释在这种情况下使用malloc()and free()... 是有意义的吗?

简而言之,如果您知道特定变量在构建时(运行时之前)的内存需求是什么,请使用静态/自动创建变量(以及相应的内存使用)。如果在运行时之前不知道需要什么大小,请使用malloc()calloc()与相应的调用free()(对于每次使用)来创建内存。这当然是一个经验法则,也是一个粗略的概括。当您获得使用内存的经验时,您会发现即使大小信息在运行时之前已知,您也会因为其他一些标准而选择动态分配。(想到尺寸)

于 2013-11-11T19:07:13.027 回答
1

首先没有必要投malloc

array = malloc(n * sizeof(char));   

我有一个问题:我为什么不这样做char array[10];

如果你不知道你想要多少存储空间,你会怎么做(比如说,如果你想要一个任意大小的数组,例如堆栈或链表)?
在这种情况下,您必须依赖malloc(在 C99 中,您可以使用可变长度数组,但对于较小的内存大小)。

该函数malloc用于在程序执行期间分配一定数量的内存。该malloc函数将从堆中请求一块内存。如果请求被批准,操作系统将保留请求的内存量。

当不再需要内存量时,您必须通过调用函数将其返回给操作系统free
很简单:当您知道数组在编译时需要保存的元素数量时,您可以使用数组。当您不知道数组在编译时需要多少个元素时,您可以将 malloc 与指针一起使用。
有关更多详细信息,请阅读使用和进行堆管理malloc()free()

于 2013-11-11T19:07:58.350 回答
1

假设您要分配 1,000 个数组。

如果您没有mallocfree ... 但需要在源中为每个数组声明,那么您必须进行 1,000 个声明。你必须给他们所有的名字。( array1, array2, ... array1000)。

动态内存管理的一般想法是在项目的数量不是您在编写程序时可以提前知道的情况下处理项目。

于 2013-11-11T19:08:01.937 回答
0

如果你事先知道你只需要一个 10 个字符的数组,你应该说char array[10]. 如果您事先不知道需要多少存储空间, malloc 很有用。如果您需要在当前函数返回后有效的存储,它也很有用。如果将数组声明为char array[10],它将在堆栈上分配。在您的函数返回后,此数据将无效。您从中获取的存储malloc空间在您调用free它之前一直有效。

此外,不需要强制转换 malloc 的返回值。

于 2013-11-11T19:07:38.440 回答
0

为什么要在 malloc 之后使用 free 可以理解为,只要你不需要它就释放内存是一种很好的风格。但是,如果您不释放内存,那么它不会造成太大伤害,但只会增加您的运行时间成本。

您也可以选择在退出程序时不释放内存。malloc() 使用堆,并且在进程退出时释放进程的完整堆。人们坚持释放内存的唯一原因是避免内存泄漏。

这里

分配误区 4:非垃圾回收程序应始终释放它们分配的所有内存。

真相:在频繁执行的代码中省略释放会导致越来越多的泄漏。他们很少被接受。但是在程序退出之前保留大部分分配内存的程序通常在没有任何干预解除分配的情况下执行得更好。如果没有免费的,Malloc 更容易实现。

在大多数情况下,在程序退出之前释放内存是没有意义的。无论如何,操作系统都会收回它。自由会在死物中触摸和翻页;操作系统不会。

结果:小心计算分配的“泄漏检测器”。一些“泄漏”是好的!


wiki在堆基础内存分配方面也有一个很好的观点:-

堆方法存在一些固有缺陷,完全源于碎片。像任何内存分配方法一样,堆会变得碎片化;也就是说,在堆上分配的空间中会有部分已使用和未使用的内存。一个好的分配器会在扩展堆之前尝试在已分配的内存中找到一个未使用的区域来使用。这种方法的主要问题是堆只有两个重要的属性:基,或虚拟内存空间中堆的开始;和长度,或它的大小。堆需要足够的系统内存来填满它的整个长度,并且它的基数永远不会改变。因此,任何大面积的未使用内存都被浪费了。如果堆的末尾存在一个小的已用段,则堆可能会“卡在”这个位置,这可能会浪费任何数量的地址空间,从几兆字节到几百字节不等。

于 2013-11-11T19:07:51.583 回答