C ++在Visual Studio中的双向链表中读取访问冲突

时间:2017-05-31 06:08:30

标签: c++ error-handling exception-handling nullpointerexception runtime-error

我可以使用g ++在Linux机器上编译我的代码并运行驱动程序就好了。在我的Windows机器上编译和运行驱动程序时,我在ptr->next方法中遇到了size()语句的读访问冲突错误。 (假设只有一个节点)在调试时,我可以按预期逐步执行while语句,在第二次传递时,即使没有节点,它也会继续ptr != nullptr

添加节点和列表size == 1时会发生此错误。

我一直在查看所有的陈述,似乎无法找到我出错的地方。有关这方面的任何信息表示赞赏!

标题

#ifndef DEQUE_H
#define DEQUE_H
#include <iostream>

using namespace std;

template <class Object>
class Deque {
 public:
  Deque( );                                   // the constructor
  Deque( const Deque &rhs );                  // the copy constructor
  ~Deque( );                                  // the destructor

  bool isEmpty( ) const;                      // checks if a deque is empty.
  int size( ) const;                          // retrieves # deque nodes
  const Object &getFront( ) const;            // retrieve the front node
  const Object &getBack( ) const;             // retrieve the tail node

  void clear( );                              // clean up all deque entries.
  void addFront( const Object &obj );         // add a new node to the front
  void addBack( const Object &obj );          // add a new node to the tail
  Object removeFront( );                      // remove the front node
  Object removeBack( );                       // remove the tail node

  const Deque &operator=( const Deque &rhs ); // assignment

 private:
  struct DequeNode {                          // a deque node
    Object item;
    DequeNode *next;
    DequeNode *prev;
  };
  DequeNode *front;
  DequeNode *back;
};

#include "deque.cpp.h"
#endif

CPP

template <class Object>
Deque<Object>::Deque( ) {                          // the constructor
  front = back = NULL;
}

template <class Object>
Deque<Object>::Deque( const Deque &rhs ) {         // the copy constructor
  front = back = NULL;
  *this = rhs;
}

template <class Object>
Deque<Object>::~Deque( ) {                         // the destructor
  clear( );
}

template <class Object>
bool Deque<Object>::isEmpty( ) const {             // check if a deque is empty
  return front == NULL;
}

template <class Object>
int Deque<Object>::size( ) const {                 // retrieves # deque nodes
    int length = 0;
    DequeNode* ptr = front;

    while (ptr != nullptr) {
        length++;
        ptr = ptr->next;
    }
    return length;
}

template <class Object>
const Object &Deque<Object>::getFront( ) const {   // retrieve the front node
  if ( isEmpty( ) )
    throw "empty queue";
  return front->item;
}

template <class Object>
const Object &Deque<Object>::getBack( ) const {    // retrieve the tail node
  if ( isEmpty( ) )
    throw "empty queue";
  return back->item;
}

template <class Object>
void Deque<Object>::clear( ) {          // clean up all entries.
  while ( !isEmpty( ) )                 // dequeue till the queue gets empty.
    removeFront( );
}

template <class Object>
void Deque<Object>::addFront( const Object &obj ) {// add a new node to  front
  // Implement the function body.
  DequeNode* newNode = new DequeNode;
  newNode->item = obj;

  // if no nodes, new node is front and back
  if (isEmpty()){
    front = back = newNode;
  }

  // if one node, new front and back are established

  else if (size() == 1){
    back->prev = newNode;
    front = newNode;
    front->next = back;
  }

  // add to front and shift right
  else {
    DequeNode* oldFront = front;
    front->prev = newNode;
    front = newNode;
    front->next = oldFront;
    }
}

template <class Object>
void Deque<Object>::addBack( const Object &obj ) { // add a new node to tail
  // Implement the function body.
  DequeNode* newNode = new DequeNode;
  newNode->item = obj;

  // if no nodes, new node is front and back
  if (isEmpty()){
    front = back = newNode;
  }

  // if one node, new front and back are established
  else if (size() == 1){
    front->next = newNode;
    back = newNode;
    back->prev = front;
  }

  // add to back and shift left
  else {
    DequeNode* oldBack = back;
    back->next = newNode;
    back = newNode;
    back->prev = oldBack;
  }
}

template <class Object>
Object Deque<Object>::removeFront( ) {  // remove the front node
  // Implement the function body.

  if (isEmpty())
    throw "empty queue"; 

  // if only one node, return item, Deque is now NULL.
  else if (size() == 1){
    DequeNode* remove = front;
    Object result = remove->item; 
    front = back = NULL;

    delete remove;
    remove = NULL;

    return result;
    }

  // remove front node, shift right
  else {
    Object result = front->item;
    DequeNode* remove = front;
    front = front->next;
    front->prev = NULL;

    delete remove;
    remove = NULL;

    return result;
    }
}

template <class Object>
Object Deque<Object>::removeBack( ) {   // remove the tail node
  // Implement the function body.

  if (isEmpty())
     throw "empty queue";

  // if only one node, return item, Deque is now NULL.
  else if (size() == 1){
      DequeNode* remove = back;
      Object result = remove->item;
      front = back = NULL;

      delete remove;
      remove = NULL;

      return result;
    }

  // remove back node, shift left
  else {
    Object result = back->item; 
    DequeNode* remove = back;
    back = back->prev;
    back->next = NULL;

    delete remove;
    remove = NULL;

    return result;
    }
}

template <class Object>
const Deque<Object> &Deque<Object>::operator=( const Deque &rhs ) { // assign
  if ( this != &rhs ) { // avoid self assignment
    clear( );
    for ( DequeNode *rptr = rhs.front; rptr != NULL; rptr = rptr->next )
      addBack( rptr->item );
  }
  return *this;
}

驱动程序

#include <iostream>
#include "deque.h"

using namespace std;

int main( ) {
  Deque<int> deque1;
  int item;

  for ( int j = 0; j < 5; j++ )
    deque1.addBack( j );
  for ( int j = 5; j < 10; j++ )
    deque1.addFront( j );

  Deque<int> deque2 = deque1;
  deque2.addBack( 10 );

  cout << "deque1: " << endl;
  while ( !deque1.isEmpty( ) )
    cout << deque1.removeFront( ) << endl;

  cout << "deque2: " << endl;
  while ( !deque2.isEmpty( ) )
    cout << deque2.removeBack( ) << endl;
}

2 个答案:

答案 0 :(得分:2)

确保在插入元素时正确设置prevnext指针。

template <class Object>
void Deque<Object>::addFront( const Object &obj ) {// add a new node to  front
  // Implement the function body.
  DequeNode* newNode = new DequeNode;
  newNode->item = obj;

  //Set these pointers to proper values depending on the state of the queue.
  newNode->next = nullptr;
  newNode->prev = nullptr;

例如,当您的队列为空并且您正在将项目插入其中时,

 // if no nodes, new node is front and back
 if (isEmpty()){
   front = back = newNode;
 }

不会初始化nextprev指针。因此,当您在迭代中到达此节点时,这些指针将不等于nullptr,您将尝试访问无效内存。

答案 1 :(得分:1)

您正在阅读未初始化的内存。

DequeNode* newNode = new DequeNode;分配新的DequeNode,但不会初始化新节点的成员(nextprev)。

你应该像这样声明DequeNode

struct DequeNode {                          // a deque node
  Object item;
  DequeNode *next = nullptr;
  DequeNode *prev = nullptr;
};

以确保nextprev指针初始化为nullptr

您应该学习如何使用调试器调试这些简单的错误。

如果它在Linux下运行,那纯属机会。可能Linux下的内存分配用0初始化新分配的内存,而在Windows上,如果程序是在调试模式下编译的,则新分配的内存将填充特殊值0xCDCDCDCD。

调试器显示此值:

enter image description here

Se this SO article,了解有关Visual Studio中未初始化内存使用哪些特殊值的更多信息。

相关问题