如果我们需要一个“tmp缓冲区”,为什么要使用“realloc”`
至于我所关心的,如果如果我们需要一个“tmp缓冲区”,为什么要使用“realloc”`,c,malloc,realloc,C,Malloc,Realloc,至于我所关心的,如果realloc失败,我们将丢失信息并realloc将缓冲区(指针)设置为NULL 考虑以下计划: #include<stdio.h> #include<stdlib.h> #include<string.h> int main(void){ char *ptr = malloc(256); if (!ptr){ printf("Error, malloc\n"); exit(1);
realloc
失败,我们将丢失信息并realloc
将缓冲区(指针)设置为NULL
考虑以下计划:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(void){
char *ptr = malloc(256);
if (!ptr){
printf("Error, malloc\n");
exit(1);
}
strcpy(ptr, "Michi");
ptr = realloc (ptr, 1024 * 102400000uL); /* I ask for a big chunk here to make realloc to fail */
if (!ptr){
printf("Houston we have a Problem\n");
}
printf("PTR = %s\n", ptr);
if (ptr){
free(ptr);
ptr = NULL;
}
}
我刚刚丢失了ptr
中的信息
现在要解决这个问题,我们应该先使用一个临时缓冲区(指针),看看我们是否得到了那块内存,如果得到了,我们可以使用它,如果没有,我们仍然可以使用主缓冲区(指针)
现在请考虑下面的程序,而不是调用<代码> ReloLC/<代码>,我在临时缓冲区(指针)上调用<代码> MalOC :
现在,我为什么要使用realloc
?
基于此上下文,使用
realloc
而不是malloc
有什么好处吗?您的问题在于如何使用realloc
。您不必将realloc
的结果分配给重新分配的同一个指针。正如您所指出的,如果realloc
失败,它甚至会带来问题。如果您立即将结果分配给ptr
,那么当出现问题时,确实会丢失以前的缓冲区。但是,如果将realloc
的结果分配给tmpPTR
,则即使realloc
失败,ptr
仍保持良好状态。使用realloc
如下:
char * ptr = malloc(256);
if(!ptr){
return 1;
}
char * tmpPTR = realloc(ptr, 512);
if(!tmpPTR){
printf("Houston, we have a problem");
// ptr is fine
}else{
ptr = tmpPTR;
}
// ptr is realloc()ed
在上面的代码中,tmpPTR
不是一个新的(临时)缓冲区,而是一个(临时)指针。如果realloc
成功,它将指向相同的缓冲区(但可能位于不同的位置),如果失败,它将为NULL
realloc
并不总是需要分配新的缓冲区,但可以更改现有的缓冲区以适应新的大小。但如果失败,则不会更改原始缓冲区
如果将malloc
与临时缓冲区一起使用,则(在本例中)至少需要256+512=768字节,并且始终需要复制旧数据realloc
可能能够重复使用旧的缓冲区,因此不需要复制,并且您不会使用超过请求的内存
您可以使用
malloc
方法,但是realloc
几乎总是更有效。realloc方案很简单。您不需要单独调用malloc
。例如,如果您最初为ptr
分配了256
字节,只需使用计数器(或下面的索引,i
)即可跟踪分配给ptr
的块中有多少内存已被使用,以及计数器何时达到限制(如果使用ptr
作为字符串,则1小于基于0的索引的最大值,或2小于最大值),realloc
下面显示了一个方案,您只需在每次达到分配限制时向ptr
添加256
额外字节:
int i = 0, max = 256;
char *ptr = malloc(max);
/* do whatever until i reaches 255 */
if (i + 1 >= max) {
void *tmp = realloc (ptr, max + 256);
if (!tmp) {
fprintf (stderr, "error: realloc - memory exhausted.\n")
/* handle error */
}
ptr = tmp;
max += 256;
}
注意:您的处理错误
可以退出任何循环以保留ptr
中的现有数据。您不需要在该点退出
现在要解决这个问题,我们应该先使用一个临时缓冲区(指针),看看我们是否得到了那块内存,如果得到了,我们可以使用它,如果没有,我们仍然可以使用主缓冲区(指针)
这不仅没有帮助,而且让事情变得更糟,因为现在你不再有指向你试图重新分配的块的指针。那么你如何释放它呢
因此:
浪费内存
需要额外分配、复制和免费
由于1,使得realloc
更有可能失败
由于指向试图重新分配的块的指针丢失,内存泄漏
因此,不,这不是处理返回NULL的realloc
的好方法。在调用realloc
时保存原始指针,以便能够理智地处理故障。realloc
的目的是避免您必须管理两个数据副本,甚至避免在可能的情况下创建它们。所以让realloc
不要这样做无论何时,他都会为你工作。与malloc
相比,realloc
的优势在于,它可能能够扩展原始动态内存区域,因此无需复制所有以前的元素;你不能用malloc
1来做这件事。而这种优化是否可用,对你来说都没有成本美国
假设您有一个以前分配的指针:
char *some_string = malloc(size); // assume non-NULL
然后
在(1)处,您用新指针更新旧指针。可能会发生两种情况:地址已有效更改(元素已自动复制)或未更改-您并不在乎。无论哪种情况,您的数据现在都位于某个\u字符串
只有实际的实现(OS/libc)知道是否有可能放大块:你看不到它,它是一个实现细节。但是,你可以检查你的实现代码,看看它是如何实现的。从技术上讲,这是不必要的,因为它执行的是完全相同的任务
我经常读取长度不确定的输入。在下面的函数示例中,我很少使用malloc()
,而是广泛使用realloc()
:
#include <stdlib.h>
#include <errno.h>
struct record {
/* fields in each record */
};
struct table {
size_t size; /* Number of records allocated */
size_t used; /* Number of records in table */
struct record item[]; /* C99 flexible array member */
};
#define MAX_ITEMS_PER_READ 1
struct table *read_table(FILE *source)
{
struct table *result = NULL, *temp;
size_t size = 0;
size_t used = 0, n;
int err = 0;
/* Read loop */
while (1) {
if (used + MAX_ITEMS_PER_READ > size) {
/* Array size growth policy.
* Some suggest doubling the size,
* or using a constant factor.
* Here, the minimum is
* size = used + MAX_ITEMS_PER_READ;
*/
const size_t newsize = 2*MAX_ITEMS_PER_READ + used + used / 2;
temp = realloc(result, sizeof (struct table) +
newsize * sizeof (result->item[0]));
if (!temp) {
err = ENOMEM;
break;
}
result = temp;
size = newsize;
}
/* Read a record to result->item[used],
* or up to (size-used) records starting at result->item + used.
* If there are no more records, break.
* If an error occurs, set err = errno, and break.
*
* Increment used by the number of records read: */
used++;
}
if (err) {
free(result); /* NOTE: free(NULL) is safe. */
errno = err;
return NULL;
}
if (!used) {
free(result);
errno = ENODATA; /* POSIX.1 error code, not C89/C99/C11 */
return NULL;
}
/* Optional: optimize table size. */
if (used < size) {
/* We don't mind even if realloc were to fail here. */
temp = realloc(result, sizeof (struct table) +
used * sizeof table->item[0]);
if (temp) {
result = temp;
size = used;
}
}
result->size = size;
result->used = used;
errno = 0; /* Not normally zeroed; just my style. */
return result;
}
#包括
#包括
结构记录{
/*每个记录中的字段*/
};
结构表{
大小\u t大小;/*分配的记录数*/
使用的大小;/*表中的记录数*/
结构记录项[];/*C99灵活数组成员*/
};
#定义每个读取的最大项目数1
结构表*读取表(文件*源)
{
结构表*result=NULL,*temp;
大小\u t大小=0;
使用的尺寸=0,n;
int err=0;
/*读循环*/
而(1){
如果(已使用+每个读取的最大项目>大小){
/*阵列大小增长策略。
*有人建议将规模扩大一倍,
*或者使用常数因子。
*在这里,最小值是
int i = 0, max = 256;
char *ptr = malloc(max);
/* do whatever until i reaches 255 */
if (i + 1 >= max) {
void *tmp = realloc (ptr, max + 256);
if (!tmp) {
fprintf (stderr, "error: realloc - memory exhausted.\n")
/* handle error */
}
ptr = tmp;
max += 256;
}
char *some_string = malloc(size); // assume non-NULL
if (realloc_needed) {
char *tmp = realloc(some_string, new_size);
if ( tmp == NULL )
// handle error
else
some_string = tmp; // (1)
#include <stdlib.h>
#include <errno.h>
struct record {
/* fields in each record */
};
struct table {
size_t size; /* Number of records allocated */
size_t used; /* Number of records in table */
struct record item[]; /* C99 flexible array member */
};
#define MAX_ITEMS_PER_READ 1
struct table *read_table(FILE *source)
{
struct table *result = NULL, *temp;
size_t size = 0;
size_t used = 0, n;
int err = 0;
/* Read loop */
while (1) {
if (used + MAX_ITEMS_PER_READ > size) {
/* Array size growth policy.
* Some suggest doubling the size,
* or using a constant factor.
* Here, the minimum is
* size = used + MAX_ITEMS_PER_READ;
*/
const size_t newsize = 2*MAX_ITEMS_PER_READ + used + used / 2;
temp = realloc(result, sizeof (struct table) +
newsize * sizeof (result->item[0]));
if (!temp) {
err = ENOMEM;
break;
}
result = temp;
size = newsize;
}
/* Read a record to result->item[used],
* or up to (size-used) records starting at result->item + used.
* If there are no more records, break.
* If an error occurs, set err = errno, and break.
*
* Increment used by the number of records read: */
used++;
}
if (err) {
free(result); /* NOTE: free(NULL) is safe. */
errno = err;
return NULL;
}
if (!used) {
free(result);
errno = ENODATA; /* POSIX.1 error code, not C89/C99/C11 */
return NULL;
}
/* Optional: optimize table size. */
if (used < size) {
/* We don't mind even if realloc were to fail here. */
temp = realloc(result, sizeof (struct table) +
used * sizeof table->item[0]);
if (temp) {
result = temp;
size = used;
}
}
result->size = size;
result->used = used;
errno = 0; /* Not normally zeroed; just my style. */
return result;
}
char * ptr = malloc(256);
if (!ptr) {
return 1;
}
char * tmpPTR = realloc(ptr, 512);
if (!tmpPTR) {
printf("Houston, we have a problem");
// ptr is fine
}
else {
ptr = tmpPTR;
}
// ptr is realloc()ed