【问题标题】:Realloc an array but do not lose the elements in it重新分配一个数组,但不要丢失其中的元素
【发布时间】:2015-05-18 04:56:43
【问题描述】:

代码:

int * data;
data = malloc(sizeof(int)*10);
int i;
for(i=0;i<10;i++)
  data[i]=i;
int * aux;
aux = realloc(data,sizeof(int)*20);
if(aux)
   data=aux;
for(i=10;i<20;i++)
  data[i]=i;

一位老师曾经告诉我“不,你不能在没有备份的情况下重新分配包含元素的数组”;我说,“哦,好的”,但现在这对我来说毫无意义。

指针指向的内存已经分配,​​所以“不可能”丢失它;如果我做一个安全的realloc 应该没有问题。

我的问题是:如果我想调整一个动态数组的大小,上面的示例代码是否有效?

【问题讨论】:

    标签: c pointers malloc realloc


    【解决方案1】:

    没关系。只需 两个 再做三件事即可使其完美,

    1. 在使用返回的指针之前检查malloc() 是否成功。
    2. 如果realloc() 失败,则不应访问具有新维度的数组。
    3. 在此代码块之后,很难确定为data 分配的内存是否已更改(20)或未更改(10)。所以,更好的方法是,而不是检查非 NULL,

      • 检查NULL作为realloc()的返回指针
      • 如果为 NULL,则停止/返回/中止 [或使用旧维度获取更多代码,如果可以的话]
      • 否则继续使用新维度。

    【讨论】:

    • 至少有一个问题你没有指出——在片段的末尾,你不知道数组的长度是 10 还是 20。这使得添加毫无意义。
    • 在代码片段后面的语句中,我们可以假设有一个指向一块数据的非空指针,但是你对原始代码的修改,你不知道那个块有多大的数据是。可能是 20,因为 malloc()realloc() 都成功了;它可能是 10,因为 malloc() 成功但 realloc() 失败。当然,您的修复程序没有写入未分配的内存(这很好!),但您不知道在后面的代码中访问 data[10] 是否安全。
    【解决方案2】:

    您的代码并不完全有效。这是一个部分注释的修改版本:

    size_t size = 10;  // Keep a record of the size of the array
    int *data = malloc(sizeof(*data) * size);
    if (data != 0)   // Always check that the allocation succeeds
    {
        for (size_t i = 0; i < size; i++)
            data[i] = i;
        size_t new_size = size * 2;  // Grow arrays by doubling as a general rule
        int *aux = realloc(data, sizeof(*aux) * new_size);
        if (aux != 0)             // Test allocation - as you did anyway
        {
            data = aux;
            // Only initialize new data if successful
            for (size_t i = size; i < new_size; i++)
                data[i] = i;
            size = new_size;      // Record new size of array
        }
    }
    
    /* At this point, if data != 0, it is safe to access data[0]..data[size-1] */
    

    您需要知道该片段末尾的数组有多大。在此版本中,如果data 不为空,则size 记录其大小。 (如果 data 为空,您现在可能应该退出了。)在您的原始代码中,您不知道数组的大小。这是一个主要问题。如果你不知道它有多大,你就不能安全地使用它。

    分配使用sizeof(*data),因此如果data 的类型改变(比如double *data),malloc() 语句的其余部分不必改变。这是不投射 malloc()realloc() 的结果的优势。

    【讨论】:

      【解决方案3】:

      基本上没问题。最后两行代码,用于初始化新值,需要在 if 语句中,以防重新分配失败。否则,您将访问原始缓冲区,该缓冲区仅分配给 10 个元素,因此您最终将访问不属于您的内存。

      【讨论】:

      • 至少有一个问题你没有指出——在片段的末尾,你不知道数组的长度是 10 还是 20。这使得添加毫无意义。
      • @JonathanLeffler - 整个代码毫无意义,我们可以认为这是演示的产物。
      • 我认为我的回答正好解决了这个问题。如果aux不是NULL,那么它是20个元素;如果是NULL,则原始(仍然分配的)缓冲区是 10 个元素,因此为什么访问第二个 10 个元素超出了数组的末尾,应该避免(即放在 if 语句中)。
      • 好吧——我不同意@HenkHolterman 或你的观点,Jim。在代码片段后面的语句中,我们可以假设有一个指向一块数据的非空指针,但是通过您对原始代码的修改,您不知道那块数据有多大。可能是 20,因为 malloc()realloc() 都成功了;它可能是 10,因为 malloc() 成功但 realloc() 失败。当然,您的修复程序没有写入未分配的内存(这很好!),但您不知道在后面的代码中访问数据是否安全[10]。
      • 哦,您的意思是在我们在 OP 中看到的任何后续代码中。当然,这是一个正确的陈述,但我认为所提供的代码只是一般如何处理 malloc/realloc 的示例。当然,生产版本应该跟踪缓冲区合法保存的元素数量,如果它打算以后以非平凡的方式访问它们。我的回答只针对 OP 的具体问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-12
      • 1970-01-01
      • 1970-01-01
      • 2016-06-24
      相关资源
      最近更新 更多