【问题标题】:How to free() a malloc()'d structured correctly?如何正确地释放()一个malloc()结构?
【发布时间】:2011-01-11 23:56:30
【问题描述】:

我有一个 malloc() 结构,在使用它们之后,我想 free() 它,但是我的程序在这里冻结了。谁能告诉我,我做错了什么?

这是我的代码:

struct data  
{  
char *filename;  
char *size;  
};   
 //primarypcs is a long type variable
struct data *primary = (struct data *)malloc( primarypcs * sizeof( struct data ) );  
memset( primary, 0, sizeof(struct data *) * primarypcs );  
...
...
...
for ( i = 0; i < primarypcs; i++ )  
{
   free( primary[i].filename );  //<----my program freezes here
   free( primary[i].size );      //<----or here
}
free( primary );  

提前致谢!

坎皮

编辑:

我怎样才能正确地为文件名和大小分配内存?

编辑2:

抱歉,我赶时间,没有告诉你你需要的所有信息。让我现在做 :) 基本上,我想创建一个应用程序,它获取两个给定驱动器/文件夹的文件列表,然后比较它们。我认为(并且仍然这样做),最简单的方法是,当我将文件名及其大小存储在上述结构中时。所以我必须为文件名和大小动态分配内存(我认为这是他们所说的),也必须为结构分配内存。

【问题讨论】:

  • 我没有看到你为 filenamesize 分配内存。
  • 是的,您的代码中有一个错误:在 malloc 中您使用的 sizeof(struct data) 似乎是正确的,但在 memset 中您使用的 sizeof(struct data*) 是大小的一半。这意味着你只将一半的内存归零,当你试图释放它时,最后 1/2 的内存会倒掉。答案应该是免费的(主要的);仅此而已
  • 如果这是 C++,你应该使用 new 和 delete。
  • @Xorlev :我已经在回答中提到了这一点。请参阅下面的答案。
  • 您需要选择 C++ 或 C 作为语言。您的示例使用 C 语言,而不是 C++。

标签: c pointers free malloc


【解决方案1】:

您并没有呈现整个代码,其中可能会出现很多错误,但其中一个错误已经很明显了。线

memset( primary, 0, sizeof(struct data *) * primarypcs );   

没有做你认为它正在做的事情。由于sizeof 中的类型错误,它没有将整个数组归零。应该是这样的

memset( primary, 0, sizeof(struct data) * primarypcs );   

sizeof 下注意没有*。由于这个错误,数组中的大多数指针都包含垃圾作为它们的初始值。如果您没有在省略的代码中将它们设置为有意义的值,您对free 的调用将收到垃圾参数并失败。

一般来说,为了减少发生此类错误的机会,最好避免在程序中提及类型名称,声明中除外。由于您的问题被标记为 C++(尽管它确实看起来像 C),因此无法摆脱 malloc 上的类型转换,但否则我会说以下看起来更好

struct data *primary = (struct data *) malloc( primarypcs * sizeof *primary );   
memset( primary, 0, primarypcs * sizeof *primary );   

另外,如果你的代码是 C++ 的,你可以通过更优雅、紧凑和可移植的方式获得相同的结果

data *primary = new data[primarypcs]();

当然,在这种情况下,您必须使用适当的 C++ 功能而不是 free 来释放内存。

【讨论】:

  • 嗨!谢谢你的帮助。这是我的错误之一,但是在您的回答更正了我的代码之后,我的程序仍然冻结了。后来我意识到我打错了一个变量,我只为 5 个项目分配了内存,但是我在结构中插入了超过 5 个项目。再次感谢您!
【解决方案2】:

结构中的字符串是如何分配的?如果它们被静态分配给常量,那么不要以这种方式释放它们,只需free (primary); 释放未被malloc'd 的东西将使堆管理器心脏骤停。

如果字符串指针是由malloc()或calloc()设置的,那是正确的方法。

【讨论】:

    【解决方案3】:

    如果你在 C++ 中这样做,你(几乎可以肯定)不应该使用类似的东西:

    data *primary = new data[primarypcs]();
    

    相反,你应该使用类似的东西:

    struct data {
        std::string filename;
        std::string size;
    };
    
    std::vector<data> primary(primarypcs);
    

    在这种情况下,您通常可以更简单地处理内存管理:在需要的范围内定义向量,当超出范围时,内存将自动释放。

    在 C++ 中使用新数组(如 new x[y])是最好的选择。曾几何时(15 年前左右)它几乎是唯一可用的工具,因此(勉强)使用它几乎是不可避免的——但那一天已经过去很久了,自从有一个真正的好使用它的理由。

    由于不可避免地会有关于“除了实现类似向量的东西”的评论,我会指出,不,即使你正在实现向量,你也不会使用新数组——你(间接地,通过分配器) 使用 ::operator new 分配原始内存,放置 new 以在该内存中创建对象,并使用显式 dtor 调用来销毁对象。

    【讨论】:

      【解决方案4】:

      正如其他人所说,您显示的 sn-p 中有两个明显错误的地方:

      1. 您不会为刚刚分配的结构的filenamesize 成员分配内存,
      2. 您的 memset() 呼叫使用了错误的大小。

      您的memset() 呼叫可以通过以下方式简化和纠正:

      memset(primary, 0, primarypcs * sizeof *primary);
      

      您的代码还有一个微妙的问题:C 标准不保证所有位为零是空指针常量(即 NULL),因此 memset() 不是设置指向的指针的正确方法NULL。做你想做的事的便携方式是:

      size_t i;
      for (i=0; i < primarypcs; ++i) {
          primary[i].filename = NULL;
          primary[i].size = NULL;
      }
      

      要为filenamesize 分配内存,这取决于你想要什么。假设您确定filename 需要n 字节,而size 需要m。然后,你的循环会变成这样:

      size_t i;
      for (i=0; i < primarypcs; ++i) {
          size_t n, m;
          /* get the values of n and m */
          primary[i].filename = malloc(n * sizeof *primary[i].filename);
          primary[i].size = malloc(m * sizeof *primary[i].size);
      }
      

      如果你愿意,你可以省略上面与sizeof *primary[i].filenamesizeof *primary[i].size 的乘法:C 保证sizeof(char) 是1。我写上面是为了完整性和filenamesize 的情况改变类型。

      另外,请注意,如果filename 是长度为k 的字符串,那么您需要(k+1) 字节,因为终止0(所以上面的n == k+1)。

      如果我猜测一下,您希望size 存储对应的filename 的长度吗?如果是这种情况,size 不应该是 char *,而是 size_t。但由于我不知道你打算如何使用filenamesize,所以我不确定。

      请务必检查malloc() 的返回值。它返回NULL 失败。为简单起见,我省略了上述代码中的检查。

      您的帖子也被标记为 C++,所以如果您愿意使用 C++,也可以使用 C++ 解决方案。

      【讨论】:

      • 嗨!我应该如何为文件名和大小正确分配内存?
      • 嗨!大小是 char* 的目的。我得到文件的大小很长,但后来我必须将它用作char,所以我将它从int转换为char,然后将它存储在结构中。
      【解决方案5】:

      将代码底部的 for 循环替换为 free (primary); 应该可以工作。

      【讨论】:

        【解决方案6】:

        那是因为您没有为filenamesize 显式分配内存。所以尝试做free( primary[i].filename );free( primary[i].size ); 会调用Undefined Behavior

        free(primary) 就够了。

        编辑

        此问题已标记为 C++。所以 C++ 的方式是使用new 而不是malloc 用于用户定义的类型。

        有关newmalloc 之间的区别,请查看this.

        C++中,你只需要写

         data *primary = new data[primarypcs](); //() for value initialization
        

        【讨论】:

        • 示例代码可以认为是ok的,假设它们单独malloc文件名。有一个 malloc 的“大小”看起来很可疑,但 size_t 可能更适合(除非它真的是一个 char 字符串)
        【解决方案7】:

        这解决了你在 memset 中的问题,这给你带来了各种各样的问题。

        memset( primary, 0, sizeof(struct data) * primarypcs );  
        

        简而言之,您在“主”结构的末尾留下了未初始化的内存。

        【讨论】:

          【解决方案8】:

          您未能对整个数组进行 m​​emset,从而导致垃圾内存指针被释放。使用 calloc 代替 malloc/memset 来避免这个错误:

          struct data *primary = calloc(primarypcs, sizeof(struct data));
          

          这既分配了又清除了内存。 如果你也想初始化所有struct data 条目:

          for (i = 0; i < primarypcs; ++i) {
              primary[i].filename = malloc(...);
              primary[i].size = malloc(...);
          }
          

          (你没有描述文件名的大小,所以我把 ... 留给你填写)。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-07-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-12-13
            • 2018-04-27
            • 1970-01-01
            相关资源
            最近更新 更多