据我了解,当被要求保留更大的内存块时,
realloc()
函数将执行以下三种不同操作之一:
if free contiguous block exists
grow current block
else if sufficient memory
allocate new memory
copy old memory to new
free old memory
else
return null
增加当前块是一个非常便宜的操作,所以这是我想利用的行为。但是,如果我要重新分配内存,因为我想(例如)在现有字符串的开头插入一个字符,我不希望
realloc()
复制内存。我最终将使用 realloc()
复制整个字符串,然后再次手动复制以释放第一个数组元素。
是否可以确定
realloc()
将做什么?如果可以的话,是否可以跨平台的方式实现?
realloc()
的行为可能取决于其具体实现。基于此的代码将是一个可怕的黑客行为,至少可以说,它违反了封装。
适合您的具体示例的更好解决方案是:
malloc()
),大于之前的缓冲区正如评论中指出的,问题中的情况3(没有记忆)是错误的;如果没有可用内存,
realloc()
将返回 NULL [问题现已修复]。
Steve McConnell 在《Code Complete》中指出,如果在
realloc()
失败时将 realloc()
的返回值保存在原始指针的唯一副本中,那么您就泄漏了内存。那就是:
void *ptr = malloc(1024);
...
if ((ptr = realloc(ptr, 2048)) == 0)
{
/* Oops - cannot free original memory allocation any more! */
}
realloc() 的不同实现会有不同的行为。唯一安全的假设是数据将总是被移动——当你realloc()内存时你总是会得到一个新的地址。
正如其他人指出的,如果您担心这一点,也许是时候看看您的算法了。
向后存储字符串会有帮助吗?
否则... 只需 malloc() 超出您需要的空间,当您用完空间时,复制到新的缓冲区。一个简单的技巧是每次将空间加倍;这非常有效,因为字符串越大(即复制到新缓冲区所需的时间越长),发生的频率就越低。
使用此方法,您还可以在缓冲区中右对齐字符串,因此可以轻松在开头添加字符。
不-如果你仔细想想,这是行不通的。在您检查它将要执行的操作和实际执行操作之间,另一个进程可能会分配内存。
在多线程应用程序中这是行不通的。在您检查它将要执行的操作和实际执行操作之间,另一个线程可以分配内存。
如果您担心这类事情,可能是时候查看您正在使用的数据结构,看看是否可以解决那里的问题。根据这些字符串的构造方式,您可以使用设计良好的缓冲区非常有效地完成此操作。
为什么不在字符串的左侧保留一些空的缓冲区空间,就像这样:
char* buf = malloc(1024);
char* start = buf + 1024 - 3;
start[0]='t';
start[1]='o';
start[2]='\0';
要将“on”添加到字符串的开头,使其成为“onto”:
start-=2;
if(start < buf)
DO_MEMORY_STUFF(start, buf);//time to reallocate!
start[0]='o';
start[1]='n';
这样,您就不必每次想要在开头进行插入时都不断复制缓冲区。
如果必须在开头和结尾都插入,只需在两端分配一些空间即可;显然,在中间插入仍然需要您重新排列元素。
更好的方法是使用链表。将每个数据对象分配在一个页面上,然后分配另一个页面并有一个指向该页面的链接(从上一页或从索引页面)。这样你就知道下一次分配何时失败,并且你永远不需要复制内存。
我认为跨平台方式是不可能的。 这里是 ulibc 实现的代码,它可能会给你一个如何以平台相关的方式执行它的线索,实际上最好找到 glibc 源代码,但这个是在谷歌搜索的顶部:)