C内存分配,分段错误/双重释放结构数组

时间:2017-08-21 12:22:56

标签: c arrays free dynamic-memory-allocation realloc

根据我的理解,Segmentation Fault就是你尚未正确分配内存,而Double free是你尝试释放已经释放的内存的时候?

增加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等等。我还需要在哪里分配内存?

3 个答案:

答案 0 :(得分:3)

  

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

仅当 realloc()失败时才会出现错误。成功后,realloc()会自动释放先前分配的块(如果有必要)(如果它是相同的块并且系统可以简单地更改大小,则可能没有必要)。

所以,常见的习语看起来像这样:

mytype *var = malloc(...);

// ...

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

// ...

free(var);

答案 1 :(得分:2)

首先, 请不要使用格式 ,如

 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指定。

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

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

答案 2 :(得分:0)

您收到双重免费错误,因为您对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
    }
}