C 语言 realloc

2024年8月28日 | 阅读 7 分钟

“realloc”是C语言中的一个标准库函数,用于重新分配动态分配的内存块。该函数接受两个参数:一个是指向先前分配的内存块的指针,另一个是需要将内存块重新分配到的新大小

该函数工作原理如下:

  • 如果传递给realloc的指针是NULL,它将表现得像malloc一样,并分配给定大小的新内存块。
  • 如果传递给realloc的大小是,它将表现得像free一样,并释放指针指向的内存块。
  • 如果传递给realloc的大小大于先前分配的内存块的大小,它将尝试扩展现有的内存块。假设由于系统内存不足而无法扩展内存块。它将分配指定大小的新内存块,将旧块的内容复制到新块,释放旧块,然后返回指向新块的引用。
  • 如果传递给realloc的大小小于或等于先前分配的内存块的大小,它将尝试收缩现有的内存块。如果内存块可以收缩,它将返回指向同一内存块的指针。如果内存块无法收缩,它将分配指定大小的新内存块,将旧块的内容复制到新块,释放旧块,并返回指向新块的指针。

需要注意的是,如果realloc无法就地扩展或收缩现有块,它可能会将内存块移动到新的位置。这意味着对旧块的任何指针或引用在调用realloc后都将失效。

示例代码,展示了“realloc”的用法:

输出

1 2 3 4 5

说明

在此示例中,我们首先使用malloc分配了一个用于容纳3个整数的内存块。之后,我们设置了整数的值并打印出来。接下来,我们使用realloc将内存块重新分配为容纳5个整数。我们设置了新整数的值并打印出来。最后,我们使用free释放内存块。

realloc的特点

realloc有各种特点。一些重要的realloc特点如下:

  • 务必检查realloc的返回值是否存在错误。如果realloc返回NULL,则表示内存分配失败,旧内存块仍然有效。在这种情况下,程序应处理错误,并可能退出或返回错误代码。
  • 当使用realloc调整内存块大小时,旧内存块的内容可能会被保留或移动到新位置。不能保证会发生哪种情况,因此您应该始终假定旧内存块可能会被移动,并相应地更新指向该块的任何指针或引用。
  • 在大多数情况下,“Realloc”比创建新的内存块并将信息从旧块传输到新块更有效。这是因为realloc可以利用旧块 adjacent 的任何未使用的内存空间,而分配新块则需要找到新的连续内存块并复制数据。
  • 当使用realloc收缩内存块时,新大小之外的任何数据都将丢失。在使用realloc时务必小心,以避免无意中丢失数据。
  • realloc是一个相对底层的函数,如果使用不当,它可能会容易出错。通常最好使用更高级的数据结构或自动处理内存管理的库,例如C++中的std::vectorJava中的ArrayList

realloc的语法

realloc的语法如下:

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

其中ptr是先前使用malloc, callocrealloc分配的内存块的指针,而size是内存块的新大小(以字节为单位)。如果分配失败,该函数将返回指向新内存块的指针或NULL

其他一些示例代码,用于说明在C语言中使用'realloc'的用法:

实现动态堆栈

'realloc'的一个常见用例是实现动态堆栈。这是一个示例:

输出

5
4
3
2
1

说明

在此实现中,我们使用malloc为堆栈及其大小为size数组分配内存。我们在push函数中使用realloc在数组变满时调整其大小。我们还实现了一个pop函数来移除并返回堆栈的顶部元素,以及一个free_stack函数来释放为堆栈及其数组分配的内存。

  • 传递给realloc的size参数可以为零。在这种情况下,realloc的行为类似于free,并释放ptr指向的内存块。
  • 如果Realloc无法分配内存,它将返回NULL,并且初始内存块保持不变。在这种情况下,务必避免覆盖原始指针,否则会导致内存泄漏。
  • 需要注意的是,ptr指向的内存块必须是使用malloc, callocrealloc分配的。
  • 使用realloc调整内存块大小时,原始块的内容将被保留,直到达到旧大小和新大小中的较小者。如果新大小大于旧大小,则额外的内存未初始化。
  • 通常最好使用临时变量来存储realloc的结果,以防其返回NULL。这可以避免覆盖原始指针并导致内存泄漏。
  • 调整数组大小时,新大小应以所需的元素数量而不是总字节数来指定。这是因为realloc处理的是指针类型,而不是字节类型。例如,如果要将整数数组的大小调整为10个元素,则应将10 * sizeof(int)作为第二个参数传递给realloc
  • 在调整数组大小时,从旧数组复制元素到新数组时,使用适当的大小非常重要。如果使用不正确的大小,您可能会复制过多的或过少的数据,从而导致内存损坏或其他错误。例如,如果您正在调整整数数组的大小并使用memcpy复制元素,则应使用sizeof(int)作为size参数。
  • 如果您正在调整结构体数组的大小,请记住,如果您添加删除字段,结构体的内存布局可能会发生变化。如果您依赖于旧的内存布局来访问结构体的字段,这可能会导致问题。在这种情况下,您可能需要使用循环手动将字段复制到新数组,而不是依赖于memcpy
  • 调整数组大小时,请记住,如果可用连续内存不足,realloc可能需要将内存块移动到新的位置。如果数组非常大,这可能会很慢,因为realloc需要将所有元素复制到新位置。如果您正在处理非常大的数组,使用malloc分配新数组并使用循环手动复制元素可能更有效。

下一个主题C中的特殊运算符