2015-06-09 3 views
-1

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

void queue::print(){ 
    if (current){ 
     std::cout << std::endl << std::endl << "+++++++++++++++++++ Webpage +++++++++++++++++++" << std::endl 
      << "URL: " << current->data.getURL() << std::endl 
      << "-----------------------------------------------" << std::endl 
      << "Title: " << current->data.getTitle() << std::endl 
      << "-----------------------------------------------" << std::endl 
      << "Content: " << current->data.getContent() << std::endl 
      << "+++++++++++++++++++++++++++++++++++++++++++++++" << std::endl << std::endl; 
    } 
    else{ 
     std::cout << std::endl << "Your not on a page. Please navigate to a page first." << std::endl; 
    } 

Теперь, если я заполнил список с двумя узлами данных, и я выполняю свою функцию печати, его 'напечатайте данные в узле очень хорошо. Однако, если я траверс к предыдущему узлу с моей GoBack() функцией:

void queue::goBack(){ 
    if (!current->previous){ 
     std::cout << "No previous page to go to!" << std::endl; 
    } 
    else{ 
     temp2 = current; 
     current = current->previous; 
    } 
} 

Это будет выполнять отлично, но когда я пытаюсь напечатать данные в узле (с той же функцией печати) Я получаю эту ошибку :

Необработанное исключение в 0x003E7926 в Web Browser.exe: 0xC0000005: Место для обнаружения нарушения доступа 0xCDCDCE19.

и визуальная студия открывает файл без расширения, с похожим на него кодом C, называемым xstring, который имеет стрелку разрыва, указывающую на строку 1754 на ней.

Теперь позвольте мне объяснить свой код немного подробнее. У меня есть пять файлов: webQueue.h, webQueue.cpp, webPage.h, webPage.cpp, & main.cpp. Все перечисленные мной функции находятся в моем файле webQueue.cpp.

Вот webQueue.h:

#include "webPage.h" 
class queue{ 
public: 
    queue(); 
    void newPage(std::string u, std::string t, std::string c); 
    void goForward(); 
    void goBack(); 
    void print(); 
private: 
    struct Node{ 
     webPage data; 
     Node* next; 
     Node* previous; 
    }; 
    Node* temp; 
    Node* current; 
    Node* temp2; 
}; 

И вот webPage.h:

#include <string> 
class webPage{ 
public: 
    webPage(); 
    webPage(std::string u, std::string t, std::string c); 
    std::string getURL(); 
    void setURL(std::string u); 
    std::string getTitle(); 
    void setTitle(std::string t); 
    std::string getContent(); 
    void setContent(std::string c); 
private: 
    std::string URL; 
    std::string title; 
    std::string content; 
}; 

Мой файл webQueue.cpp включает в себя:

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

Мой файл webPage.cpp включает в себя только webPage.h и мой файл main.cpp (который содержит мою исполняемую функцию) включают:

#include <iostream> 
#include <string> 
#include "webQueue.h" 

Хотя эти отношения могут показаться немного запутанными, все они должны быть действительными. Файлы cpp связаны с их заголовочными файлами с тем же именем (при условии, что файл заголовка существует), а также main.cpp, связанный с webQueue.h и webQueue.h, связанным с webPage.h. Я не вижу, что я делаю неправильно с моим кодом, хотя это, вероятно, только потому, что мне сложно понять, как работают указатели. Я предполагаю, что ошибка в коде моих функций print(), goBack() и goForward() (хотя я не могу проверить функцию goForward() до тех пор, пока не исправлю функцию goBack()), но я не могу скажите, что случилось.

Любая помощь, которую вы, ребята, можете дать, будет очень благодарна, так как я в тупике. Вот ссылка на все файлы, чтобы вы могли протестировать эту программу для себя и посмотреть, есть ли у меня какие-либо другие функции с ошибками: https://www.dropbox.com/s/yekrz6dln1v9npk/webQueue.zip?dl=0

+2

Добро пожаловать на переполнение стека. Я не могу переоценить важность обучения для подготовки [минимального полного примера] (http://stackoverflow.com/help/mcve). Поставьте свой код на самый простой пример, который все еще воспроизводит ошибку, и ошибка, вероятно, будет очевидна; если это не так, вы можете опубликовать небольшой, автономный пример для нас, чтобы посмотреть. – Beta

+1

@Beta Вот почему я включил загрузку Dropbox. – Larrimus

+2

В Visual Studio есть классные отладочные материалы, такие как точки останова, которые вы можете установить в строке перед тем, как ваша программа получит необработанное исключение. И список часов, чтобы вы могли видеть значения переменных в вашей программе. Пожалуйста, используйте их, чтобы увидеть, соответствуют ли значения, как вы ожидали, перед их печатью. – KompjoeFriek

ответ

1

Неправильное управление Node.

Одна небольшая проблема в том, что queue::goBack() и queue::goForward() не проверка, если current является нулевым, прежде чем получить доступ к его поля, так что ваш код будет вылетать, если пользователь выбирает «вернуться» или «идти вперед», прежде чем выбрать «перейти к веб-странице "(по крайней мере print() проверяет значение null).Поэтому добавьте эти проверки и, возможно, даже обновите printMenu(), чтобы даже не выводить эти параметры, когда очередь не имеет доступной текущей страницы.

Но, что более важно, ваша реализация queue::newPage()полностью сломана. Когда current не равно нулю, вы настраиваете next элемент этого узла, чтобы указать на самой вместо нового узла вы создали, и вы не устанавливая previous поле нового узла на всех, не говоря уже, чтобы указать на существующий узел, который он вставляется после.

Вы также должны избавиться от temp и temp2 членов класса queue. В первую очередь, они не принадлежат. Они полезны только внутри queue::newPage() (queue::goBack() не обязательно использовать temp вообще, как и goForward()), поэтому их следует заменить на локальные переменные внутри queue::newPage(). Еще лучше, их можно просто удалить вообще, так как queue::newPage() может быть реализован без их использования вообще.

Ваше queue реализация должна выглядеть как это вместо (и это даже не считая копирования/перемещения семантику, либо - см rule of three/five/zero):

#include "webPage.h" 

class queue { 
public: 
    queue(); 
    void newPage(std::string u, std::string t, std::string c); 
    void goForward(); 
    void goBack(); 
    void print(); 
private: 
    struct Node { 
     webPage data; 
     Node* next; 
     Node* previous; 
    }; 
    Node* current; 
}; 

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

queue::queue() { 
    current = nullptr; 
} 

void queue::newPage(std::string u, std::string t, std::string c) { 
    Node* n = new Node; 
    n->data = webPage(u, t, c); 
    n->next = nullptr; 
    n->previous = nullptr; 

    if (current) { 
     if (current->next) { 
      n->next = current->next; 
      current->next->previous = n; 
     } 
     n->previous = current; 
     current->next = n; 
    } 

    current = n; 
} 

void queue::goBack() { 
    if ((current) && (current->previous)) { 
     current = current->previous; 
    } 
    else { 
     std::cout << "No previous page to go to!" << std::endl; 
    } 
} 

void queue::goForward() { 
    if ((current) && (current->next)) { 
     current = current->next; 
    } 
    else { 
     std::cout << "No next page to go to!" << std::endl; 
    } 
} 

void queue::print() { 
    if (current) { 
     std::cout << std::endl << std::endl 
      << "+++++++++++++++++++ Webpage +++++++++++++++++++" << std::endl 
      << "URL: " << current->data.getURL() << std::endl 
      << "-----------------------------------------------" << std::endl 
      << "Title: " << current->data.getTitle() << std::endl 
      << "-----------------------------------------------" << std::endl 
      << "Content: " << current->data.getContent() << std::endl 
      << "+++++++++++++++++++++++++++++++++++++++++++++++" << std::endl << std::endl; 
    } 
    else { 
     std::cout << std::endl << "You are not on a page. Please navigate to a page first." << std::endl; 
    } 
} 

И затем, в то время как вам на нем, вы должны переписать queue, чтобы прекратить использование управления ручным узлом вообще и использовать вместо этого класс std::list:

#include "webPage.h" 
#include <list> 

class queue { 
public: 
    void newPage(std::string u, std::string t, std::string c); 
    void goForward(); 
    void goBack(); 
    void print(); 
private: 
    std::list<webPage> data; 
    std::list<webPage>::iterator current; 
}; 

#include "webQueue.h" 
#include <iostream> 
#include <iterator> 

void queue::newPage(std::string u, std::string t, std::string c) { 
    webPage p(u, t, c); 
    if (data.empty()) { 
     data.push_back(p); 
     current = data.begin(); 
    } 
    else { 
     current = data.insert(std::next(current), p); 
    } 
} 

void queue::goBack() { 
    if ((!data.empty()) && (current != data.begin())) 
     current = std::prev(current); 
    else 
     std::cout << "No previous page to go to!" << std::endl; 
} 

void queue::goForward() { 
    if (!data.empty()) { 
     std::list<webPage>::iterator iter = std::next(current); 
     if (iter != data.end()) { 
      current = iter; 
      return; 
     } 
    } 
    std::cout << "No next page to go to!" << std::endl; 
} 

void queue::print() { 
    if (!data.empty()) { 
     std::cout << std::endl << std::endl 
      << "+++++++++++++++++++ Webpage +++++++++++++++++++" << std::endl 
      << "URL: " << current->data.getURL() << std::endl 
      << "-----------------------------------------------" << std::endl 
      << "Title: " << current->data.getTitle() << std::endl 
      << "-----------------------------------------------" << std::endl 
      << "Content: " << current->data.getContent() << std::endl 
      << "+++++++++++++++++++++++++++++++++++++++++++++++" << std::endl << std::endl; 
    } 
    else { 
     std::cout << std::endl << "You are not on a page. Please navigate to a page first." << std::endl; 
    } 
} 
+0

Спасибо! Это фиксировало мой код, но почему стандартный список лучше? – Larrimus

+1

Я тоже немного смущен этой строкой кода: 'current-> next-> previous = n;'. Это просто эквивалент «current-> next = n;» и «current-> previous = n;»? Мне жаль беспокоить вас, я только начал изучать C++ пять месяцев назад. – Larrimus

+0

Класс 'std :: list' лучше использовать, потому что это * стандартизованный * класс, определенный в спецификации STL C++, и поэтому он переносится ко всем компиляторам на C++, имеет предсказуемое поведение, обрабатывает все грязные детали надлежащего управление узлами и т. д. И нет, 'current-> next-> previous = n;' НЕ совпадает с 'current-> next = n; current-> previous = n; '. Посмотрите ДЕЙСТВИТЕЛЬНО, что делают эти утверждения ... –

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