【问题标题】:What is the better memory allocation method in C when the input data exceed the original allocated space? [duplicate]当输入数据超过原始分配的空间时,C 中更好的内存分配方法是什么? [复制]
【发布时间】:2018-12-19 09:11:29
【问题描述】:

我知道 C 中有一个通用策略来处理输入数据(例如文本)超出原始分配空间的情况。这是重新分配更多空间。

#include <stdlib.h>
#include <stdio.h>

#define BUF_SIZE 1024

void check_buffer(char *buffer) 
{
    if (!buffer) {
        fprintf(stderr, "lsh: allocation error\n");
        exit(EXIT_FAILURE);
    }
}

char *read_line() 
{
    int bufsize = BUF_SIZE;
    int position = 0;
    char *buffer = malloc(sizeof(char) * bufsize);
    int c;

    check_buffer(buffer);

    while (1) {
        c = getchar();

        if (c == EOF || c == '\n') {
            buffer[position] = '\0';
            return buffer;
        } else {
            buffer[position] = c;
        }
        position++;

        if (position >= bufsize) {
            bufsize += BUF_SIZE; // Or `bufsize *= 2;`?
            buffer = realloc(buffer, bufsize);

            check_buffer(buffer);
        }
    }
}

那么扩大原始空间的更好方法是什么? bufsize += BUF_SIZE 还是 bufsize *= 2?哪种方式更有效?

【问题讨论】:

  • 我只做bufsize += 1。这取决于。关于系统、环境、使用、程序、开发人员。许多图书馆以不同的方式处理这个问题,例如。见cs50。前任。在 C++ 中,他们只是 new bufsize+1 -> 复制所有数据 -> delete old_storage
  • 不要 realloc 使用指针本身,使用临时指针,例如void *tmp = realloc(buffer, bufsize * 2); if (!tmp) { perror ("realloc-buffer"); buffer[position] = '\0'; break; } buffer = tmp; bufsize *= 2; 继续前进。

标签: c allocation


【解决方案1】:

哪种方式更有效?

这是一个非常模棱两可的问题。对什么有效?请注意,性能不是一个好的答案,因为它几乎与“有效”一样模棱两可。

你不能说一种方法比另一种更好。两者各有利弊,很大程度上取决于实际情况和BUF_SIZE的值。

选择其中一个。如果您遇到性能问题,请尝试其他方法并尝试调整 BUF_SIZE 的值。但在您这样做之前,请分析代码以查看重新分配是否真的是问题。

第三种选择介于两者之间。你可以这样做:

bufsize = bufsize*log(bufsize);
realloc(buffer, bufsize);

第四种是使用指数增长直到达到阈值然后切换:

if(bufsize > THRESHOLD)
    bufsize += LINEAR_INCREASE;
else
    bufsize *= 2;

纯指数增长可能导致问题的一种情况是,如果您已经有一个非常大的缓冲区。那么下一次重新分配可能会失败,或者导致其他问题。

另外,请记住通过检查返回指针是否为 NULL 来检查重新分配(以及初始分配)是否确实有效。并且永远不要将缓冲区分配给返回值。如果重新分配失败,您也会丢失当前分配。你可以这样做:

void * ptr = realloc(buffer, bufsize);
if(ptr) buffer = ptr;
else { // Handle the fact that reallocation failed }

如果您的内存量非常有限,那么执行以下操作可能是个好主意:

int increase = LINEAR_INCREASE;
void * ptr;
do {
    ptr = realloc(buffer, increase);
    increase /= 2; // If realloc failed, try with half the increase
} while(!ptr && increase > 0)
if(ptr) buffer = ptr;
else { /* Handle the fact that reallocation failed */ }

【讨论】:

  • 您在else 部分中的// cmets 有效地注释掉了} 右括号。​​
  • @pmg 当您将评论交换为合适的代码时,这将不是问题。
【解决方案2】:

当您第三次重新分配并且您已经在第二次分配了 2048 字节内存时会发生什么?

bufsize += BUF_SIZE; //this will be 2048 + 1024 =3072
bufsize *= 2; // this will be 2048*2 = 4096

您显然想在哪里分配 3072 字节的内存。

【讨论】:

  • 我误解了这个问题吗?
  • 显然他想将旧结果相乘并得到1024 * 2 * 2 = 4096,这就是它的完成方式,例如。 cs50。我们可以在 github 上找到许多此类方法的示例,请参阅google results。问题是What is the better way to expand the original space? bufsize += BUF_SIZE or bufsize *= 2?
  • @KamilCuk 我一直认为内存重新分配应该是额外的而不是指数的。
  • @kiranBiradar 你的理由是什么?
  • 我也是; ) 因为我通常在内存很少的嵌入式系统中工作,所以分配 16 或 32 字节对我来说有很多的不同(如果我有 malloc 的话)。我做bufsize += 1。但这是一种意见。但在某些系统上,realloc 非常昂贵,最好偶尔分配一次非常大的块。
猜你喜欢
  • 2020-08-28
  • 2014-07-06
  • 1970-01-01
  • 2010-09-15
  • 1970-01-01
  • 1970-01-01
  • 2013-01-12
  • 1970-01-01
相关资源
最近更新 更多