如何在此自定义堆栈实现中正确分配更多内存?

时间:2016-07-01 21:40:03

标签: c++ arrays memory data-structures stack

我正在努力使每次超出尺寸时我的Stack尺寸增加一倍。我需要创建一个新的堆栈来保存旧堆栈,但是需要加倍。需要删除旧堆栈。下面的代码一直给我错误

"堆栈(17854,0x7fff77cd0300)malloc: *对象0x1001054b0的错误:未释放指针被释放 * 在malloc_error_break中设置一个断点来调试"

此外,每次运行程序时生成的随机数都相同。帮助!

#include <iostream>
using namespace std;

const int DEFAULT_SIZE = 100;

template< class T >
class Stack {
public:
    Stack( int = 10 );  // default constructor (stack size 10)
    // destructor
    ~Stack() {
            delete [] stackPtr;
    }

    bool push( const T& );
    bool pop( T& );
    int pop();

    // determine whether Stack is empty
    bool isEmpty() const {
            return top == -1;
    }

    // determine whether Stack is full
    bool isFull() const  {
            return top == size - 1;
    }

private:
    int size;     // # of elements in the stack
    int top;      // location of the top element
    T *stackPtr;  // pointer to the stack
};

// constructor
template< class T >
Stack< T >::Stack( int s ) {
    size = s > 0 ? s : 10;
    top = -1;  // Stack initially empty
    stackPtr = new T[ size ]; // allocate memory for elements
}

template< class T >
bool Stack< T >::push( const T &pushValue ) {
    if ( !isFull() ) {
        stackPtr[ ++top ] = pushValue;
        return true;
    }

    T *newPtr = new T[size*2];
    newPtr = stackPtr;
    delete [] stackPtr;
    return true;
}

template< class T >
bool Stack< T >::pop( T &popValue ) {
    if ( !isEmpty() ) {
        popValue = stackPtr[ top-- ];  // remove item from Stack
        return true;
    }

    return false;
}

template <class T>
int Stack< T >::pop() {
    return stackPtr[--size];
}

int main() {
    Stack<int> s;
    int i = 0;
    for (i=0; i < DEFAULT_SIZE; i++) {
        s.push( rand() % 100 +1 );
    }

    for (i=0; i < DEFAULT_SIZE; i++) {
        cout << s.pop() << " , ";
        if (i % 20 == 0) {
            cout << endl;
        }
    }
}

3 个答案:

答案 0 :(得分:6)

看看这段代码,它来自你的push实现(它是你分配更多内存的部分):

1: T *newPtr = new T[size*2];
2: newPtr = stackPtr;
3: delete [] stackPtr;
4: return true;

在视觉上,这是发生了什么。在第1行之前,事情看起来像这样:

 +----------+       +-----+-----+-----+-----+
 | stackPtr | ----> | 137 | 271 | 281 | 284 |
 +----------+       +-----+-----+-----+-----+

执行第1行后,事情如下:

 +----------+       +-----+-----+-----+-----+
 | stackPtr | ----> | 137 | 271 | 281 | 284 |
 +----------+       +-----+-----+-----+-----+
 +----------+       +-----+-----+-----+-----+-----+-----+-----+-----+
 |  newPtr  | ----> |  ?  |  ?  |  ?  |  ?  |  ?  |  ?  |  ?  |  ?  |
 +----------+       +-----+-----+-----+-----+-----+-----+-----+-----+

执行第2行后,事情如下:

 +----------+       +-----+-----+-----+-----+
 | stackPtr | --+-> | 137 | 271 | 281 | 284 |
 +----------+   |   +-----+-----+-----+-----+
 +----------+   |   +-----+-----+-----+-----+-----+-----+-----+-----+
 |  newPtr  | --+   |  s  |  o  |     |  a  |  l  |  o  |  n  |  e  |
 +----------+       +-----+-----+-----+-----+-----+-----+-----+-----+

糟糕。你刚刚孤立了一堆记忆。

执行第3行后,事情如下:

 +----------+        
 | stackPtr | --+->    kablooie! deleted memory.
 +----------+   |
 +----------+   |
 |  newPtr  | --+
 +----------+     

请注意,当你完成后,你最终得到了孤立的内存(所有的?),你的stackPtr变量现在指向死记忆。糟糕。

要解决此问题,您需要进行一些更改。首先,当你写了

newPtr = stackPtr;

我的感觉是你打算将旧数组中的所有元素复制到新数组中。不幸的是,如上所述,你所写的并不符合你的想法。要解决此问题,您需要一次一个地明确移动元素。考虑使用for循环来执行此操作 - 一次从stackPtr一个元素读取并写入newPtr中的相应条目。

其次,您需要更改stackPtr,以便在炸毁之前分配的内存后,将其指向新分配的内存。一种方法是编写

stackPtr = newPtr;
在为stackPtr释放内存后

这里还有另外一个问题。请注意,在分配新阵列后,您从未真正更新size。这意味着虽然您将获得一个全新的阵列,但您实际上并不记得它有多大。因此,在完成其他所有操作后,请确保更新size,使其比以前大两倍。

代码中可能还有其他问题,但我怀疑这有助于您入门。要记住的一些事情:

  1. 使用指针时绘制图片绝对不会伤害。
  2. 注意不要将“指定指针”与“数组的复制元素”混淆。
  3. 记得要做所有必要的簿记。
  4. 祝你好运!

答案 1 :(得分:2)

T *newPtr = new T[size*2];
newPtr = stackPtr;
delete [] stackPtr;
return true;

stackPtr指向它现在已删除的原始内存结束。您也永远不会将旧内存的内容实际移动到新内存中。它应该是这样的:

T* newPtr = new T[size*2];
std::move(stackPtr, stackPtr + size, newPtr);
delete[] stackPtr;
stackPtr = newPtr;

关于rand每次都返回同样的事情;你永远不会播种随机发生器。在致电srand之前,您需要在计划开始时致电rand

答案 2 :(得分:0)

这段代码显然是错误的:

T *newPtr = new T[size*2];
newPtr = stackPtr;
delete [] stackPtr;

您分配一个新指针,然后立即丢弃它,然后将其删除。因此新分配的内存被泄露,stackPtr已被释放且无效。你也没有在size发生变化时更新(好吧,如果你没有像筛子一样泄漏内存,那么你有时会使用size top {1}}。