7

我有一个结构 malloc()'d,在使用它们之后,我想 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:

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

4

8 回答 8

7

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

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

没有做你认为它正在做的事情。由于输入错误,它没有将整个数组归零sizeof。这很可能是

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

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

通常,为了减少此类错误的机会,最好避免在程序中提及类型名称,声明除外。由于您的问题被标记为 C++(即使它看起来确实像 C),所以不可能摆脱类型转换 on malloc,但否则我会说以下看起来更好

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

并且,作为旁注,如果您的代码是 C++,您可以以更优雅、紧凑和可移植的方式获得相同的结果

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

当然,在这种情况下,您必须使用适当的 C++ 功能而不是free.

于 2010-02-02T02:31:51.407 回答
3

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

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

于 2010-02-02T02:29:26.870 回答
2

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

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

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

struct data {
    std::string filename;
    std::string size;
};

std::vector<data> primary(primarypcs);

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

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

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

于 2010-02-02T02:54:13.760 回答
1

正如其他人所说,您显示的代码段中有两个明显错误的地方:

  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;
}

filename要为and分配内存size,这取决于您想要什么。假设您确定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)它的字节,因为终止0n == k+1如上)。

如果我猜测,您要size存储相应的长度filename吗?如果是这样,size不应该是 achar *而是 a size_t。但是由于我不知道您打算如何使用filenameand size,所以我不确定。

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

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

于 2010-02-02T02:54:47.097 回答
0

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

于 2010-02-02T02:32:03.980 回答
0

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

就够free(primary)了。

编辑

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

对于两者之间的差异newmalloc看看这个。

C++中,您只需要编写

 data *primary = new data[primarypcs](); //() for value initialization
于 2010-02-02T02:32:12.043 回答
0

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

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

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

于 2010-02-02T02:44:31.657 回答
0

您未能 memset 整个数组,导致垃圾内存指针被释放。使用 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(...);
}

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

于 2010-02-02T05:36:10.767 回答