【问题标题】:What's the advantage of malloc?malloc的优点是什么?
【发布时间】:2013-09-13 04:41:56
【问题描述】:

为某些数据分配内存有什么好处。相反,我们可以使用它们的数组。

喜欢

 int *lis;
 lis = (int*) malloc ( sizeof( int ) * n );

 /* Initialize LIS values for all indexes */
 for ( i = 0; i < n; i++ )
 lis[i] = 1;

我们可以使用一个普通的数组。

嗯,我不明白 malloc 是如何工作的,实际上是什么。所以解释它们对我来说会更有益。

假设我们在上面的代码中只用n 替换sizeof(int) * n,然后尝试存储整数值,我可能会遇到什么问题?有没有办法直接从内存分配的空间打印存储在变量中的值,例如这里是lis

【问题讨论】:

  • 在极少数情况下,也许,但除非n 是编译时常量,否则普通数组将无法工作。 std::vector 会(就像std::unique_ptr&lt;int[]&gt; 一样)。
  • 我建议只做一个谷歌搜索来解释 malloc 的作用,我不建议在任何代码中使用它...使用共享指针来处理内存管理
  • 如果您没有分配足够的内存,您将在分配的内存之外进行写入。当然你不能认为这是一个好主意。这将是未定义的行为 - 任何事情都可能发生。
  • malloc 和 C++ 不是最好的朋友。
  • 简单的答案是,在 C++ 中,您从不使用malloc,除非您正在实现自定义分配器。在这种情况下,唯一可接受的解决方案是std::vector&lt;int&gt; lis( n );

标签: c++ arrays malloc dynamic-allocation variable-length-array


【解决方案1】:

您的问题似乎是将动态分配的 C 样式数组与可变长度数组进行比较,这意味着这可能就是您要查找的内容:Why aren't variable-length arrays part of the C++ standard?

不过, 标签会产生最终的答案:改用std::vector 对象。

只要可能,避免动态分配和丑陋的内存管理责任〜>尝试利用具有自动存储持续时间的对象。另一个有趣的阅读可能是:Understanding the meaning of the term and the concept - RAII (Resource Acquisition is Initialization)


“假设我们在上面的代码中将 sizeof(int) * n 替换为 n,然后尝试存储整数值,我可能会遇到什么问题?”
- 如果您仍然认为 n 是可以存储在此数组中的整数数量,您很可能会遇到未定义的行为

【讨论】:

    【解决方案2】:

    答案很简单。本地1 数组分配在您的堆栈上,这是为您的程序预先分配的一小块内存。除了几千个数据,你真的不能在堆栈上做很多事情。对于更多的数据,您需要从堆栈中分配内存。

    这就是malloc 所做的。

    malloc 分配一块你要求的内存。它返回一个指向该内存开头的指针,可以将其视为类似于数组。如果您写入超出该内存的大小,则结果是未定义的行为。这意味着一切都可以正常工作,否则您的计算机可能会爆炸。尽管您很可能会遇到分段错误错误。

    从内存中读取值(例如用于打印)与从数组中读取相同。例如printf("%d", list[5]);

    在 C99 之前(我知道问题标记为 C++,但可能您正在学习 C-compiled-in-C++),还有另一个原因。你不可能在堆栈上有一个可变长度的数组。 (即使现在,堆栈上的可变长度数组也不是很有用,因为堆栈很小)。这就是为什么对于可变内存量,您需要malloc 函数来分配所需的内存,其大小在运行时确定。

    本地数组或任何本地变量之间的另一个重要区别是对象的生命周期。局部变量的作用域一结束就无法访问。 malloced 对象一直存在,直到它们成为 freed。这在几乎所有不是数组的数据结构中都是必不可少的,例如链表、二叉搜索树(和变体)、(大多数)堆等。

    malloced 对象的一个​​示例是 FILEs。一旦您调用fopen,保存与打开文件相关的数据的结构将使用malloc 动态分配并作为指针(FILE *)返回。


    1 注意:非本地数组(全局或静态)是在执行前分配的,因此它们实际上无法在运行时确定长度。

    【讨论】:

    • 在函数之外定义的数组呢?
    • @trojanfoe,我添加了一条注释。
    • 您似乎在断言差异是数组可以容纳的数据量,这是不正确的;静态分配的数组可以容纳与堆上分配的数组一样多的容量。主要区别在于它们的大小可以在运行时确定,并且可以以任意复杂度创建新的对象 (structs);使用静态定义的数组无法完成的事情。
    • @trojanfoe,也许按照标准,但实际上没有实现。随着 C99 中可变长度数组的引入,您的第一点不再是问题。第二点并不完全正确。新对象可以很容易地创建为局部变量。它使它们的寿命比需要malloc 的本地存储更长,而不仅仅是分配它们。不过,我也会写这篇文章。
    【解决方案3】:

    我假设你在问 c maloc() 的目的是什么: 假设您想从用户那里获取输入,现在分配一个该大小的数组:

    int n;
    scanf("%d",&n);
    int arr[n];
    

    这将失败,因为 n 在编译时不可用。来了malloc() 你可以写:

    int n;
    scanf("%d",&n);
    int* arr = malloc(sizeof(int)*n);
    

    其实malloc()在堆区动态分配内存

    【讨论】:

    • 1) 您需要将大小乘以n。 2) 不要使用 C 风格的演员表。 (3)不要使用malloc,但无论如何。)
    • ... 或者如果你正在编写 C,do 使用 C 风格的强制转换,do 使用 malloc,但是 不要转换它的返回值。
    【解决方案4】:

    我认为,更根本的是,除了堆栈与堆以及变量与常量问题(以及您不应该在 C++ 中使用 malloc() 一开始的事实)之外,本地数组不再是函数退出时存在。如果你返回一个指向它的指针,那么一旦调用者接收到它,该指针就会变得无用,而使用malloc()new 动态分配的内存仍然有效。例如,您无法使用本地数组实现像 strdup() 这样的函数,或者明智地实现链接表示列表或树。

    【讨论】:

      【解决方案5】:

      一些较旧的编程环境根本不提供malloc 或任何等效功能。如果您需要动态内存分配,您必须自己在巨大的静态数组之上编写代码。这有几个缺点:

      • 静态数组大小对程序可以在任何时候处理的数据量设置了一个硬性上限,而无需重新编译。如果您曾经尝试在 TeX 中做一些复杂的事情并收到“超出容量,抱歉”消息,这就是原因。
      • 操作系统(例如它曾经的操作系统)必须一次性为静态数组保留所有空间,无论是否全部使用。这种现象导致“过度使用”,其中操作系统 假装 分配了您可能需要的所有内存,但如果您实际尝试使用超过可用内存,则会终止您的进程。为什么会有人想要那个?然而它在 90 年代中期的商业 Unix 中被宣传为一个特性,因为这意味着巨大的 FORTRAN 模拟可能需要比你那极小的 Sun 工作站更多的内存,可以毫无问题地在小实例大小上进行测试。 (假设您会在 Cray 上运行 big 实例,而该实例实际上有足够的内存来应对。)
      • 动态内存分配器很难很好地实现。看看jemalloc paper,了解它有多毛茸茸。 (如果您想要自动垃圾收集 it gets even more complicated。)这正是您希望大师为每个人的利益编写一次的代码。

      所以现在即使是非常准系统的嵌入式环境也可以为您提供某种动态分配器。

      但是, 是一种很好的心理自律。动态内存的过度使用会导致效率低下,这种情况通常很难在事后消除,因为它已融入架构中。如果手头的任务看起来不需要动态分配,也许它不需要。

      然而,在你真正应该使用动态内存分配的时候可能会导致它自己的问题,例如对字符串的长度施加硬性上限,或者在你的 API 中加入不可重入性(比较gethostbynamegetaddrinfo)。

      所以你必须仔细考虑。

      【讨论】:

        【解决方案6】:

        我们可以使用一个普通的数组

        在 C++ 中(至少今年是这样),数组具有静态大小;因此从运行时值创建一个:

        int lis[n];
        

        不允许。一些编译器允许将其作为非标准扩展,明年将成为标准;但是,目前,如果我们想要一个动态大小的数组,我们必须动态分配它。

        在 C 语言中,这意味着与 malloc 混在一起;但你问的是 C++,所以你想要

        std::vector<int> lis(n, 1);
        

        分配一个大小为 n 的数组,其中包含初始化为 1 的 int 值。

        (如果你愿意,你可以用new int[n]分配数组,完成后记得用delete [] lis释放它,如果抛出异常要特别注意不要泄漏;但是生命太短暂了废话。)

        嗯,我不明白 malloc 是如何工作的,实际上是什么。所以解释它们对我来说会更有益。

        C 中的malloc 和C++ 中的new 从“空闲存储”中分配持久内存。与局部变量的内存不同,它会在变量超出范围时自动释放,这种情况会一直存在,直到您明确释放它(C 中的free,C++ 中的delete)。如果您需要数组比当前函数调用更有效,这是必要的。如果数组非常大,这也是一个好主意:局部变量(通常)存储在堆栈上,大小有限。如果溢出,程序将崩溃或出错。 (而且,在当前的标准 C++ 中,如果大小不是编译时常量,则它是必需的。

        假设我们在上面的代码中只用n 替换sizeof(int) * n,然后尝试存储整数值,我可能会遇到什么问题?

        您没有为n 整数分配足够的空间;因此假设您拥有的代码将尝试访问超出分配空间末尾的内存。这将导致未定义的行为;运气好的话会崩溃,运气不好的话会损坏数据。

        有没有办法直接从分配的内存空间打印存储在变量中的值,例如这里是lis

        你的意思是这样的?

        for (i = 0; i < len; ++i) std::cout << lis[i] << '\n';
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-08-31
          • 2014-01-24
          • 2018-02-25
          • 1970-01-01
          • 2020-02-07
          • 2010-09-29
          • 2010-11-29
          相关资源
          最近更新 更多