Нарушение прав чтения C ++ в односвязном списке - PullRequest
0 голосов
/ 05 апреля 2020

Я пишу программу о создании списка стран, в моем коде, похоже, нет ошибок, но при отладке я получаю сообщение об ошибке: Возникло необработанное исключение: нарушение прав чтения p было 0xFFFFFFFFFFFFFFFF, после ввода некоторых значений. Может ли кто-нибудь дать мне подсказку или найти мне ошибку?

#include <cstring>
#include <string>
using namespace std;

Это моя структура Provice.

struct Province
{
    int Code;
    string Name;
    int Pop;
    float Area;
};
struct node
{
    struct Province data;
    node* next;
};
struct List
{
    node* head;
    node* tail;
};
void Init(List &l)
{
    l.head = NULL;
    l.tail = NULL;
}
void add_tail(List& l, node* p)
{
    if (l.head == NULL)
    {
        l.head = p;
        l.tail = p;
    }
    else
    {
        l.tail->next = p;
        l.tail = p;
    }
}

Я думаю, у меня возникли проблемы при создании узла здесь без инициализации значения, это правильно?

void inputListProvinces(List& l)
{
    int n;
    cin >> n;
    int i = 0;
    while(i<n)
    {
        node* p = new node;
        cin >> p->data.Code;
        cin.ignore();
        getline(cin, p->data.Name);
        cin.ignore();
        cin >> p->data.Pop;
        cin >> p->data.Area;
        add_tail(l, p);
        i++;
    }
}

И здесь происходит ошибка, но я не знаю, как исправить.

void outputListProvinces(List& l)
{
    node* p = l.head;
    while (p != NULL)
    {
        cout << p->data.Code << '\t'; /*Unhandled exception thrown: read access violation.
p was 0xFFFFFFFFFFFFFFFF*/

        cout << p->data.Name << '\t';
        cout << p->data.Pop << '\t';
        cout << p->data.Area << '\t';
        cout << endl;
        p = p->next;
    }
}
void outputProvince(node* p)
{
    cout << p->data.Code << '\t';
    cout << p->data.Name << '\t';
    cout << p->data.Pop << '\t';
    cout << p->data.Area << '\t';
}
void outputProvincesMore1MillionPop(List& l)
{
    node* p = l.head;
    while (p != NULL)
    {
        if (p->data.Pop > 1000)
        {
            outputProvince(p);
            cout << endl;
        }
        p = p->next;
    }
}
node* findProMaxArea(List& l)
{
    node* n = l.head;
    node* p = l.head;
    while (p != NULL)
    {
        if (p->data.Area > n->data.Area)
        {
            n = p;
        }
        p = p->next;
    }
    return n;
}



int main()
{
    List L;
    Init(L);
    inputListProvinces(L);
    cout << "List of provinces:" << endl;
    cout << "ID\t|Province\t|Population\t|Area" << endl;
    outputListProvinces(L);

    cout << "Provinces with a population of more than 1 million:" << endl;
    outputProvincesMore1MillionPop(L);

    cout << "The largest province:" << endl;
    node* p = findProMaxArea(L);
    if (p) outputProvince(p);

    return 0;
}

1 Ответ

2 голосов
/ 05 апреля 2020

Ошибка node никогда не инициализирует указатель next. Вы можете рассчитывать на то, что он будет NULL, если вы установите его на NULL, а последний node в списке ДОЛЖЕН быть NULL, иначе программа не сможет найти конец List и выйдет из нее. в странный мир Неопределенное поведение .

Безопасное исправление: добавьте конструктор в node, чтобы убедиться, что next всегда инициализируется.

struct node
{
    struct Province data;
    node* next;
    node(node* n = NULL): next(n)
    {
    }
};

Там Есть и другие исправления, например, проверка l.tail->next = NULL; в конце inputListProvinces, но я не думаю, что это действительно стоит уменьшения накладных расходов, учитывая медленный ввод-вывод консоли.

И если вы это сделаете что, тогда вы должны также свернуть Init в List в качестве конструктора:

struct List
{
    node* head;
    node* tail;
    List(): head(NULL), tail(NULL)
    {
    }
};

Это должно оставить вас с проблемой плохого размещения cin.ignore(), потребляющего персонажа, который вам не нужен потребляется.

Примечание: замените NULL на nullptr, если доступно для вашего компилятора и целевой версии C ++ Standard. nullptr удаляет ошибки, которые могут возникнуть в результате прославления NULL 0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...