【问题标题】:Storing return values (void pointers) from malloc从 malloc 存储返回值(空指针)
【发布时间】:2015-07-20 14:51:17
【问题描述】:

我应该如何存储从malloc 返回的pointers?我有一个小型解析器,它允许在源文件中嵌套includes,这意味着第一个源文件可以包含foo,然后foo 可以包含bar 等等。

此功能迫使我在打开新文件时保持分配给每个文件的内存不变——因此分配新的内存,并继续解析它们,直到打开最后一个文件并解析最后一行,然后我可以从最后打开的文件开始freeing 内存。

我首先想到的是实现一个堆栈来跟踪分配的内存。当我这样做是为了学习 C 时,我开始阅读如何存储来自 malloc 的返回指针,但是围绕“如何投射 malloc”之类的类似主题有很多噪音,我找不到任何有用的东西。

然后我检查了malloc 文档,它说malloc 返回void 指针,但据我所知,通常不建议使用 void 指针,因为您无法取消引用 void 指针。

我认为我不需要取消引用 malloc 指针,因为我只需要将它们传递给 free 就可以了,但是我想知道是否有任何众所周知的解决方案将这些指针存储在我的堆栈中?

目标只是通过堆栈跟踪分配的内存,因此可以随时弹出并在需要时释放指向最近分配的内存的指针。

【问题讨论】:

    标签: c pointers memory-management malloc void-pointers


    【解决方案1】:

    您不得取消引用void * 或在带有强制转换的表达式中使用它们。但是您可以将它们存储为其他指针。但是,我怀疑您已经将它们分配给MyType *myptr = malloc(...),那么为什么不将它们存储为MyType *?但是,如果您有一个解析器并且真的不再需要内存(这实际上是您编写的),那么您为什么要保留内存呢?尽快释放它会更有效率。而且您不需要为它们添加额外的结构。

    如果由于块是不同的类型而遇到问题,您可以查看匿名结构/联合(自 C99 起),它允许一些基本的类派生,因此您可以存储对象并在以后处理它们而无需强制转换。如果使用 gcc,您可能还会发现 -fplan9-extensions 非常吸引人(我喜欢那些!)。如果使用得当,这将大大提高类型安全性。但请注意,您将离开 ISO 路径! (但是,使用武力)。

    【讨论】:

    • 感谢您的回答。我实际上需要保留记忆。想象一下,我首先打开第一个文件,然后在解析过程中我必须打开另一个文件。在这里我不能释放分配给第一个文件的内存,对吧?否则我将无法在完成包含文件后继续解析它。
    • 好的,所以您确实可以在存储时访问数据。是的,这样一个堆栈就可以了,但你确实应该存储正确的类型,通常将void * 存储在某个地方并不是一个好主意。您应该只在非常受控的条件下(尽可能避免使用它)将其用作函数参数/(结果),但要存储类型良好的指针。哦,关于char,记住这些可以签名或不签名!没关系,如果您不对它们使用可能产生负面结果的算术运算。
    • 太好了,所以你推荐unsigned char -- 考虑到我不会做任何指针运算或char 就足够了吗?
    • 您应该使用最适合您需要的类型。如果你只有char,那没关系。但是,根据您的问题,我希望您至少希望存储文本和当前位置的索引。这需要一个结构(无论如何这可能是一个好主意,因为它可以很容易地扩展)。请记住,C 允许将灵活的数组成员作为最后一个成员。所以实际上没有额外指针(和 malloc)的开销。
    • 我没有谈论指针运算。请记住 char 无论如何都不是指针类型。没有冒犯,但如果你在将这些东西分开时遇到问题,你可能会对符号和语义感到更舒服。 (老实说:无意冒犯!)
    【解决方案2】:

    当你使用 malloc 时,你是在请求一块你打算存储东西的内存。 malloc 函数是通用的,它既不知道也不关心你打算在它给你的内存中存储什么类型的对象。指向 void 的指针 (void*) 返回类型是 malloc 通用性质的体现。例如,如果内存要包含很长的字符串,您可能会选择接受指向 char* 类型变量的指针。强类型强制您将 void* 显式转换为 char*。如果您想创建一个指针堆栈,那么 - 继续该示例 - 您将拥有一个 char* 项堆栈。 free 函数接受一个指向 void (void*) 的指针,但转换规则说指向任何东西的指针都可以隐式转换为指向 void 的指针,所以你可以简单地传递你的 char* 指向 免费 的指针,一切都很好。

    底线 - 就 malloc 而言,存储它返回的指针没有正确或错误的方式......这完全取决于您打算如何处理内存;解决方案的设计将决定处理指针的最佳方法。

    【讨论】:

    • 不,将 (void *) 转换为任何其他类型实际上 not 获得更多类型安全性。它实际上违背了这一点,因为它掩盖了返回类型的变化(这是 - 授予 - 对于 malloc() 不太可能,但对于其他函数可能非常好)。该标准明确允许在没有类型转换(和返回)的情况下分配 void *。这实际上是 void * 允许的唯一操作。好的,在第二部分中你做对了
    • 我只是想让我的答案集中在问题的重点上。同意,强制转换可能会给您带来麻烦,但是当您使用 malloc 时,您还要做什么?至少 C++ 有 new 可以为您提供请求类型的分配,但这是另一回事。
    • @Zenilogix 感谢您的回答。我有char *,所以我可以简单地拥有一个chars 数组并存储指针,对吗?由于void 是最宽的可用指针,当我将char * 传递给free 时它不会被损坏。我理解正确吗?
    • 你需要char *,而不是char!还有它的void *void 本身不是变量的有效数据类型。将其视为“无”(与 NULL 不同,基本上意味着“无效”)。是的,void * 与其他 normal 指针兼容。旁注可能是特殊的其他指针,例如可能具有不同属性的嵌入式系统。
    • @Mahdi:很抱歉很挑剔,但这在这个领域很有帮助。
    猜你喜欢
    • 1970-01-01
    • 2016-07-08
    • 1970-01-01
    • 2014-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    相关资源
    最近更新 更多