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

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

据我了解,Segmentation Fault 是指您尚未正确分配内存,而 Double free 是指您尝试释放已经释放的内存?

增加结构数组大小的正确方法是什么,where/which 您实际需要释放的部分?

我有一个结构:

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 = . . .) 有效,但显然是错误的,因为我没有释放任何东西,对吧?

但是当我尝试使用注释掉的代码时,出现了双重 Free 错误

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

The line I'm using now (entries = . . . ) works, but is obviously wrong because I'm not freeing anything, right?

错误仅当 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,

The realloc function returns ... a null pointer if the new object could not be allocated.

[....] If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged.

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

The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by 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
    }
}