首页 > 解决方案 > 当使用 realloc 减少数组时,内存会发生什么?

问题描述

我想知道当你重新分配 -1 你的数组时内存会发生什么。根据我读过的关于 realloc 的所有内容,我认为指针仍然指向内存中的同一位置(函数不需要寻找另一块内存,因为该内存块可用且足够),如果我错了,请告诉我。我的问题是:被删除的数组片段是被删除了(就像使用 free() 一样)还是值保持不变并且这块内存正在为 malloc、calloc 等的未来操作共享?

编辑:我还有一个问题。此功能是否正常工作?它应该删除先前被数组的下一个元素覆盖的数组元素。对整个数组执行此操作,最后一个元素与最后一个元素相同,最后一个元素被删除。PicCounter 是已经上传到程序的图片数量。看一下这个:

int DeletePicture(struct Picture **tab, int *PicCounter)
{
int PicToDelete;
printf("Enter the number of pic to delete ");
scanf("%d", &PicToDelete);
for (int i = PicToDelete - 1; i < (*PicCounter) - 2; i++)
{
    (*tab)[i] = (*tab)[i + 1];
}

struct Picture *temp;
temp = realloc(*tab, ((*PicCounter)-1) * sizeof(*temp));
if (temp != NULL)
{
    *tab = temp;
 //That doesn't delete the element, because in main I can still print it
 //like e.g. tab[lastelement]. 
    (*PicCounter)--;
    printf("Picture has been deleted\n");
    return 0;
}
else
{
    printf("Memory reallocation error\n");
    return 1;
}
}

标签: carraysmemoryfreerealloc

解决方案


关于void *realloc(void *ptr, size_t size),C 标准在 C 2018 7.22.3.5 第 2 和 3 段中说:

realloc函数释放 所指向的旧对象,ptr并返回一个指向具有 指定大小的新对象的指针size。新对象的内容应与释放前旧对象的内容相同,直至新旧大小中的较小者。新对象中超出旧对象大小的任何字节都具有不确定的值。

如果ptr是空指针,则realloc函数的行为类似于malloc指定大小的函数。否则,如果ptr与内存管理函数先前返回的指针不匹配,或者如果空间已通过调用freeorrealloc函数被释放,则行为未定义。如果size为非零且未分配新对象的内存,则不会释放旧对象。如果size为零并且未分配新对象的内存,则由实现定义是否释放旧对象。如果旧对象未被释放,则其值应保持不变。

当您要求减小先前分配的对象的大小时,这意味着:

  • 返回的指针可能与原始指针相同,也可能不同。(见下文讨论。)

  • C 标准允许将释放的内存部分重新用于其他分配。是否重用取决于 C 实现。

  • C 标准未指定是否立即覆盖已释放内存部分中的值。当然,用户realloc可能不依赖于有关该内存的任何行为。

讨论

当内存分配减少时,内存分配例程在记住释放的内存是空闲的同时简单地返回相同的指针当然看起来“容易”。但是,内存分配系统相当复杂,因此可能涉及其他因素。例如,假设:

  • 为了在没有太多开销的情况下支持许多小型分配,内存分配系统可能会创建一个用于 1 到 4 字节分配的内存池、另一个用于 5 到 8 字节分配的内存池、另一个用于 8 到 16 字节分配的内存池和一个通用池对于更大的尺寸。对于较大的大小,它可能会单独记住每个分配,自定义其大小并使用各种数据结构管理它们。对于较小的尺寸,它可能只为每个保留一个位图,每个位指示是否分配了其对应的四字节(或八或 16)区域。在这样的系统中,如果您释放 16 字节分配中的 8 个字节,内存分配软件可能会将数据移动到 8 字节池中的某个位置。

  • 在任何内存分配系统中,如果您在分配结束时仅释放几个字节,则可能没有足够的字节来利用 - 跟踪您释放的几个字节所需的数据结构可能比这几个字节大。因此,让它们可供重用是不值得的。内存分配系统只是将它们保存在块中,尽管它可能会记住块中的数据实际上比为其保留的空间要小一些。


推荐阅读