繁体   English   中英

C内存分配,分段错误/结构双精度释放

[英]C Memory assignment, Segmentation Fault / Double Free In Array of Structs

据我了解,“分段错误”是指您尚未正确分配内存,而“双重释放”是指您尝试释放已释放的内存时?

增大Structs数组大小的正确方法是什么?您实际上需要在哪里/哪些零件上释放零件?

我有一个结构:

struct Data {
    // Some variables
} 

我正在用以下方法初始化这些结构的数组:

int curEntries = 100;
int counter = 0; 
struct Data *entries = (struct Data *)malloc(curEntries * sizeof(struct Data));

当我从bin文件中将数据读取到此数组中并填充每个结构时,该程序将运行,直到需要100多个结构为止。 当时,我有以下代码来重新分配数组:

if (counter == curEntries - 1) { // counter = current index, curEntries = size of the array
    entries = (struct Data *)realloc(entries, curEntries * 2 * sizeof(struct Data));
    // struct Data *temp = (struct Data *)realloc(entries, curEntries * 2 * sizeof(struct Data));
    // free(entries);
    // entries = temp;
    // free(temp);
}

我现在正在使用的行(entries =。。。)有效,但是显然是错误的,因为我没有释放任何东西,对吗?

但是,当我尝试使用注释掉的代码代替时,却出现了两次“免费”错误

最后,(因为有一系列自动测试),显然我还需要在代码的其他部分中使用malloc等。 我/我还应该在哪里分配内存?

我现在正在使用的行(entries =。。。)有效,但是显然是错误的,因为我没有释放任何东西,对吗?

仅当 realloc()失败时,这是错误的。 如果成功的话, realloc() 在必要时自动释放先前分配的块(如果是同一块,系统可以简单地改变它的大小可能是没有必要的)。

因此,常见的用法如下:

mytype *var = malloc(...);

// ...

mytype *tmp = realloc(var, ...);
if (!tmp)
{
    free(var);
    return -1; // or whatever error
}
var = tmp;

// ...

free(var);

首先, 请不要使用类似

 pointerVar = realloc (pointerVar , newsize);  // use the same pointer variable

因为如果realloc()失败,您也将擦除实际的指针。

对于realloc()失败的情况,从C11第7.22.3.5章开始,

如果无法分配新对象,则realloc函数返回...空指针。

[....]如果无法分配用于新对象的内存,则不会释放旧对象,并且其值不变。

使用realloc的正确方法是

  tempPtr = realloc (oldPtr, newSize);

  if ( tempPtr )  //allocation successful, oldPtr is `free()`-d can be reused now
  {
      oldPtr = tempPtr;
  } // and continue using `oldPtr`
  else
  {
      // some error handling
      // can still make use of `oldPtr`
   }

就是说,如果成功分配了新内存,则realloc()会自行清理以前的内存分配,而无需释放它。

引用C11 ,同一章

 void *realloc(void *ptr, size_t size); 

realloc函数取消分配 ptr指向的旧对象 ,并返回一个指向具有size指定size新对象的指针

因此,如果您注释掉了代码

struct Data *temp = (struct Data *) realloc(entries, curEntries * 2 * sizeof(struct Data));
  //assume success, memory pointed to by entries will be automatically freed

free(entries);
   // now, you're trying to free already freed memory, UB....

entries = temp;
free(temp);

您会得到一个双重释放错误,因为对realloc()调用成功,因此先前的指针已被释放,而您却调用了free(entries) 库有时可以确定某个块已被释放,但是这种健全性检查并不总是有效的。 C标准对此不提供任何保证,将释放的指针传递给free()具有未定义的行为。

在具有内存保护的系统上,当您尝试读写尚未分配给进程的内存地址或对该进程无效的内存地址时,可能会发生分段错误。 在库可以确定该块已被释放之前,取消引用释放块的指针可能会导致分段错误。

重新分配数组的方案应为:

size_t curEntries = 100; // size of the array
size_t counter = 0;      // current index

...

if (counter == curEntries) {
    // array is full, try and reallocate to a larger size
    size_t newSize = curEntries * 2;
    struct Data *newArray = realloc(entries, newSize * sizeof(*newArray));
    if (newArray == NULL) {
        // cannot reallocate, out of memory.
        // handle this error, entries is still valid.
        abort();
    } else {
        // array was reallocated possibly to a different address
        // entries is no longer a valid pointer
        entries = newArray;     // update array pointer
        curEntries = newSize;   // update number of entries
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM