2016-02-21 2 views
2

Для одного из моих классов программирования мы должны разработать программу, которая может проходить через предоставленные «стресс-тесты», которые написал наш инструктор.Исключение C++: нарушение доступа к чтению. это было nullptr

Мы работаем с узлами и связанными списками, но в отличие от любого из видео YouTube, на которое я смотрел эту тему.

Я пару раз вырываю волосы за последние несколько дней, пытаясь понять, что не так с моей программой, но мне не повезло.

Вот код для моего файла node.cpp (не включает node.h)

#include "Node.h" 

Node::Node() { 
    m_value = 0; 
    m_next = nullptr; 
} 

void Node::setValue(int val) { 
    m_value = val; 
} 

int Node::getValue() const { 
    return m_value; 
} 

void Node::setNext(Node* prev) { 
    m_next = prev; 
} 

Node* Node::getNext() const { 
    return m_next; 
} 

Вот мой LinkedList.cpp

#include <iostream> 
#include <vector> 
#include "LinkedList.h" 

LinkedList::LinkedList() { 
    m_front = nullptr; 
    m_size = 0; 
} 

LinkedList::~LinkedList() { 
    // Deconstructor 
    m_size = 0; 
    Node* a = m_front; 
    Node* b = a->getNext(); 
    while (a->getNext() != NULL) { 
     delete a; 
     a = b; 
     b = b->getNext(); 
    } 
    delete a; 
    a = NULL; 
} 

bool LinkedList::isEmpty() const{ 
    if (m_size == 0) { 
     return true; 
    } 
    else { 
     return false; 
    } 
} 

int LinkedList::size() const { 
    return m_size; 
} 

bool LinkedList::search(int value) const { 
    if (m_size == 0) { 
     return false; 
    } 
    else if (m_size == 1) { 
     if (m_front->getValue() == value) { 
      return true; 
     } 
     else { 
      return false; 
     } 
    } 
    else { 
     Node* a = m_front; 

     for (int i = 0; i < m_size; i++) { 
      if (a->getValue() == value) { 
       return true; 
      } 
      else { 
       a = a->getNext(); 
      } 
     } 
     return false; 
    } 
} 

void LinkedList::printList() const { 
    std::cout << "List: "; 
    if (m_size == 0) { 
     // Print Nothing 
    } 
    else if (m_size == 1) { 
     std::cout << m_front->getValue(); 
    } 
    else { 
     Node* a = new Node(); 
     a = m_front; 
     int b = m_front->getValue(); 
     std::cout << b << ", "; 

     while (a->getNext() != NULL) { 
      a = a->getNext(); 

      if (a->getNext() == NULL) { 
       std::cout << a->getValue(); 
      } 
      else { 
       std::cout << a->getValue() << ", "; 
      } 
     } 
    } 
    std::cout << std::endl; 

} 

void LinkedList::addBack(int value) { 
    Node* a = new Node(); 
    a->setValue(value); 
    if (m_size == 0) { 
     m_front = a; 
    } 
    else { 
     Node* b = new Node(); 
     b = m_front; 
     while (b->getNext() != NULL) { 
      b = b->getNext(); 
     } 
     b->setNext(a); 
    } 
    m_size++; 
} 

void LinkedList::addFront(int value) { 
    Node* a = new Node(); // Check later 

    a->setNext(m_front); 
    a->setValue(value); 
    m_front = a; 
    m_size++; 

} 

bool LinkedList::removeBack() { 
    if (m_size == 0) { 
     return false; 
    } 
    else { 
     Node* a = new Node(); 
     Node* b = new Node(); 
     a = m_front; 
     while (a->getNext() != NULL) { 
      b = a; 
      a = a->getNext(); 
     } 
     b->setNext(nullptr); 
     delete a; 
     a = NULL; 
     m_size--; 
     return true; 
    } 
} 

bool LinkedList::removeFront() { 
    if (m_size == 0) { 
     return false; 
    } 
    else { 
     Node* a = new Node(); 
     a = m_front; 
     m_front = m_front->getNext(); 
     delete a; 
     a = NULL; 
     m_size--; 
     return true; 
    } 
} 
std::vector<int> LinkedList::toVector() const { 
    if (m_size == 0) { 
     std::vector<int> b; 
     return b; 
    } 
    else { 
     std::vector<int> a(m_size); 
     Node* b = new Node(); 
     b = m_front; 
     for (int i = 0; i < m_size; i++) { 
      a[i] = b->getValue(); 
      b = b->getNext(); 
     } 
     return a; 
    } 
} 

В принципе, я проверил мой программа сама по себе, и я смог создать связанный список и запустить все свои функции добавления и удаления и распечатать списки просто отлично. Моя проблема заключается в том, что я запускаю тест, который дал нам наш инструктор, и он выглядит так, как будто в момент, когда у меня возникают проблемы (эти печатные сообщения находятся в другом файле, но все, что им кажется, это распечатать переданные строковые аргументы)

int score = 0; 
const int MAX_SCORE = 90; 

std::cerr << "\n\n=========================\n"; 
std::cerr << " RUNNING TEST SUITE \n"; 
std::cerr << "=========================\n\n"; 

//Run test and award points where appropriate 
score += test1() ? 2 : 0; 
score += test2() ? 2 : 0; 
score += test3() ? 3 : 0; 

Это продолжается для 18 тестов, но моя программа никогда не «делает» ее первой. Он проходит первый тест, а затем внезапно выдает ошибку.

bool Test_LinkedList::test1() 
{ 
    LinkedList list; 
    bool isPassed = false; 

    printTestMessage("size of empty list is zero"); 

    isPassed = list.size() == 0; 
    printPassFail(isPassed); 

    return (isPassed); 
} 

Я на самом деле получить этот вывод, прежде чем он выходит из строя

========================= 
    RUNNING TEST SUITE 
========================= 

Test 1: size of empty list is zero: PASSED 

Так проходит первый тест, но никогда не делает его оттуда. Я имею в виду то, что я пытался бросить сообщение cout около

score += test1() ? 2 : 0; 
std::cout << "Done with test 1" 
score += test2() ? 2 : 0; 
score += test3() ? 3 : 0; 

Но это никогда не выводится. Вместо того, чтобы моя программа брейки и Visual Studio всплывает с сообщение о том,

Exception thrown: read access violation. 

this was nullptr. 

If there is a handler for this exception, the program may be safely continued. 

Затем он указывает мне на мой метод в node.cpp, который

Node* Node::getNext() const { 
    return m_next; 
} 

К сожалению, я знаю, что это много текста чтобы читать, но прямо сейчас я не в тупик, и мне не хватает времени на работу в рабочее время, поскольку это должно быть ранним завтра утром.

Редактировать: я попытался пропустить первый тест и запустить его. Он проходит через следующие 6 тестов, но затем терпит неудачу 7-го (8-го) с той же точной ошибкой.

bool Test_LinkedList::test8() 
{ 
    LinkedList list; 
    bool isPassed = false; 

    printTestMessage("search returns false on empty list"); 

    isPassed = !list.search(42); 
    printPassFail(isPassed); 
    return (isPassed); 
} 
+0

Я думаю, что это происходит сбой в test2 потому, что прошло сообщение печатается. Когда вы выполняете 'std :: cout <<" Готово с тестом 1 ", вы успешно печатаете это, но stdio буферизируется, и текст никогда не выводит его на экран. Вам нужно очистить буфер так: 'std :: cout <<« Готово с тестом 1 »<< std :: endl;', после чего вы увидите текст. –

+0

Лучше надеюсь, что ваш профессор не попытается скопировать или скопировать назначение «LinkedList» ... –

+0

Возможно, самым важным файлом является node.h –

ответ

7

У деструктора LinkedList есть несколько проблем. Во-первых, бессмысленно установить m_size на 0 и a на NULL, так как они оба уйдут в конце деструктора.Более важно то, что код будет пытаться разыменования нулевого указателя, когда список пуст:

Node* a = m_front; // okay, gets that head pointer 
Node* b = a->getNext(); // bang!! 

Вот уборщик способ написать это:

Node* a = m_front; 
while (a != NULL) { 
    Node *temp = a->getNext(); 
    delete a; 
    a = temp; 
} 
+0

Ну вот и все! Мой код работает сейчас и проходит каждый тест. Спасибо! Я предполагаю, что я действительно не понял, как деструктор работал вообще. –

+0

Можете ли вы объяснить мне, почему 'Узел * b = a-> getNext();' сбой программы. Я предположил, что если a был узлом, то даже если a имел nullptr, поскольку это getNext(), тогда b будет просто установлен на nullptr. Неужели это не так? –

+1

@DamianVu - конструктор по умолчанию устанавливает 'm_front' значение NULL. Если в списке не было добавлено никаких объектов при его уничтожении, то 'm_front' по-прежнему остается NULL, поэтому' a' равно NULL, а 'a-> getNext()' имеет неопределенное поведение. –

Смежные вопросы

 Смежные вопросы