您可以为堆上已经存在的数组分配内存吗

时间:2019-10-28 04:25:06

标签: c++ arrays

int main(){
  int * x = new int[3];

  for(int i = 0; i < 5; ++i){
      x = new int[i];
      x[i] = i;
      cout << i << endl;
  }
}

所以说我在堆上分配了一个整数数组,容量为3个整数,如x所示。

现在说我有这个for循环,我想在其中将x的值更改为i。

现在,当我自行运行此代码时,它会运行,并且可以像我想要的那样打印0、1、2、3、4。

我想知道的是,当我为0、1、2时执行新的int [i]时,因为x [0],x [1],x [2]已经分配在堆上了,我要在堆中新建三个地址吗?

谢谢!

4 个答案:

答案 0 :(得分:1)

int main(){
  int * x = new int[3];

  for(int i = 0; i < 5; ++i){
      x = new int[i];
      x[i] = i;
      cout << i << endl;
  }
}
Running it
-> An array of size 3 is created on the heap 
-> An array of size 0 is created on the heap
-> The 0 index of array size 0 is equal to 0
-> Print 0
-> An array of size 1 is created on the heap
-> The 1 index of array size 1 is equal to 1
-> Print 1
.
.
.
-> An array of size 4 is created on the heap
-> The 4 index of array size 4 is equal to 4
-> Print 4

我不确定这是否是您的意图,但正如其余评论所述,存在内存泄漏和未定义的行为。

我认为您正在尝试实现的是

#include <iostream> 
#include <vector>  

int main() 
{ 
    std::vector<int> g1; //initialises a vector called g1
    for (int i = 1; i <= 5; i++) {
        // Adds i to the vector, expands the vector if 
        // there is not enough space
        g1.push_back(i);
        // Prints out i 
        std::cout<<i<<std::endl;
    }

答案 1 :(得分:1)

每次new时,您都在请求内存,并且系统正在分配内存块(它可能会失败,这是另一种情况),并为您提供指向该内存的初始地址的指针,请记住这一点当您new时。因此,这里最初是new由3个int组成的数组,然后在循环中再次new 5次,这将返回5个新的内存地址(即5个不同的内存块)。因此,您需要处理6个新地址(不同大小的内存块)。绝对不是您想要的东西。因此,您应该在循环中使用第一个分配,而没有任何更多的new,在这种情况下,您应该事先知道数组的范围。因此,要使其自动化,可以使用vector,当您将元素推入其中时,它会不断增长。 请参考vector

一个旁注:当您new做某事时,您应该自己保护该内存,因此new通常是不受启发的,请查看smart pointers以确保代码安全

答案 2 :(得分:1)

  

您可以为堆上已经存在的阵列分配内存吗?

答案:是(但不是您的操作方式...)

无论何时已经分配了内存,为了扩大或减小组成给定内存块的分配大小,您必须(1)分配所需大小的新内存块,并且(2)复制现有内存块(3)释放原始块之前,将块分配到新分配的块(最大为新分配的块的大小)。本质上,由于C ++中没有等效于realloc的语言,因此您只需要自己做即可。

在您的示例中,从分配大小为3-int开始,您可以进入for循环并创建一个临时块来容纳1-int(比循环索引大一),并且将x中适合您新tmp块的现有字节数复制到tmp。然后,您可以delete[] x;并将新的临时内存块的开始地址分配给x(例如x = tmp;

从您的帖子继续的一个简短示例可能是:

#include <iostream>
#include <cstring>

int main (void) {

    int nelem = 3,                  /* var to track no. of elements allocated */
        *x = new int[nelem];        /* initial allocation of 3 int - for fun */

    for (int i = 0; i < 5; i++) {

        nelem = i + 1;                          /* update nelem */

        /* create temporary block to hold nelem int */
        int *tmp = new int[nelem];              /* allocate tmp for new x */
        memcpy (tmp, x, i * sizeof *tmp);       /* copy i elements to tmp */
        delete[] x;                             /* free x */

        x = tmp;                                /* assign tmp to x */
        x[i] = i;                               /* assign x[i] */

        for (int j = 0; j < nelem; j++)         /* output all */
            std::cout << "  " << x[j];
        std::cout  << '\n';
    }

    delete[] x;     /* free x */
}

注意:在第一次迭代中,从x复制了个字节-很好。您可以在前面加上一个if (i) memcpy(如果您愿意)

使用/输出示例

$ ./bin/allocrealloc
  0
  0  1
  0  1  2
  0  1  2  3
  0  1  2  3  4

内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于任何分配的内存块,您都有2个职责:(1)始终保留指向起始地址的指针因此,(2)当不再需要它时可以释放

当务之急是使用一个内存错误检查程序来确保您不尝试访问内存或不在分配的块的边界之外/之外写,尝试读取或基于未初始化的值进行条件跳转,最后,以确认您释放了已分配的所有内存。

对于Linux,valgrind是正常选择。每个平台都有类似的内存检查器。它们都很容易使用,只需通过它运行程序即可。

$ valgrind ./bin/allocrealloc
==6202== Memcheck, a memory error detector
==6202== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6202== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==6202== Command: ./bin/allocrealloc
==6202==
  0
  0  1
  0  1  2
  0  1  2  3
  0  1  2  3  4
==6202==
==6202== HEAP SUMMARY:
==6202==     in use at exit: 0 bytes in 0 blocks
==6202==   total heap usage: 7 allocs, 7 frees, 72,776 bytes allocated
==6202==
==6202== All heap blocks were freed -- no leaks are possible
==6202==
==6202== For counts of detected and suppressed errors, rerun with: -v
==6202== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认已释放已分配的所有内存,并且没有内存错误。

仔细检查一下,如果还有其他问题,请告诉我。

答案 3 :(得分:0)

我将通过一些注释将您的代码抛给您,希望可以使您有所了解。

import firebase from 'firebase'
import 'firebase/storage'

export function putFileInStorage(path, file) {
  let storage = firebase.storage()
  return new Promise((resolve, reject) => {
    let refToFile
    try {
      refToFile = storage.ref().child(`${path}/${file.name}`)
      refToFile
        .put(file)
        .then(res => {
          resolve(res)
        })
        .catch(err => {
          reject(err)
        })
    } catch (error) {
      reject(error)
    }
  })
}