C ++异常0xC00000FD:堆栈溢出(参数:0x00000001,0x00C02F30)

时间:2018-12-13 01:39:25

标签: c++

这是针对学校项目的。我有一个叫做buddy的类和一个链接列表buddyList。在调试时,我遇到了一些我认为已正确解决的nullptr异常,但最后我尝试调试时,遇到了此异常。我该怎么做才能解决此问题? 请记住,其中一些代码是通过讲师提供的,并且该项目的目标是向现有的类中添加特定的方法。谢谢!

// buddy.h

    private void button1_Click(object sender, EventArgs e)
    {
        Regex regex1 = new Regex("^[a-zA-Z ]+$");
        Regex dat = new Regex("^(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])([0-9]{2})[-]([0-9]{5})$");
        Regex epasts = new Regex(@"^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$");

        // Use a boolean to determine whether there is an error
        var valid = true;

        if (!regex1.IsMatch(textBox1.Text))
        {
            valid = false;
            label5.ForeColor = Color.Red;
            label5.Text = "Incorrectly entered name!";
        }
        else
        {
            label5.Text = "";
        }

        if (String.IsNullOrEmpty(textBox1.Text))
        {
            valid = false;
            label5.ForeColor = Color.Red;
            label5.Text = "Name wasn't entered!";
        }

        if (!regex1.IsMatch(textBox2.Text))
        {
            valid = false;
            label6.ForeColor = Color.Red;
            label6.Text = "Surname entered incorrectly!";
        }
        else
        {
            label6.Text = "";
        }

        if (String.IsNullOrEmpty(textBox2.Text))
        {
            valid = false;
            label6.ForeColor = Color.Red;
            label6.Text = "No surname!";
        }

        if (!dat.IsMatch(textBox3.Text))
        {
            valid = false;
            label7.ForeColor = Color.Red;
            label7.Text = "Incorrect code!";
        }
        else
        {
            label7.Text = "";
        }

        if (String.IsNullOrEmpty(textBox3.Text))
        {
            valid = false;
            label7.ForeColor = Color.Red;
            label7.Text = "Not entered!";
        }

        if (!epasts.IsMatch(textBox4.Text))
        {
            valid = false;
            label8.ForeColor = Color.Red;
            label8.Text = "Incorrectly entered email!";
        }
        else
        {
            label8.Text = "";
        }

        if (String.IsNullOrEmpty(textBox4.Text))
        {
            valid = false;
            label8.ForeColor = Color.Red;
            label8.Text = "Email not entered!";
        }

        // Now you can check if there is an error 
        if (valid)
        {

            // This doesn't make any sense - because the user can ONLY click ok 
            //if (MessageBox.Show("Data is being saved", "Data saving", MessageBoxButtons.OK) == DialogResult.OK)
            // I think you maybe meant something like this? 
            if (MessageBox.Show("Data is being saved", "Data saving", MessageBoxButtons.OKCancel) == DialogResult.OK)
            {
                // And here - I'm assuming you would save the data somewhere and then clear the textboxes? 
                textBox1.Text = "";
                textBox2.Text = "";
                textBox3.Text = "";
                textBox4.Text = "";
            }
        }
        else
        {
            MessageBox.Show("Please correct the errors and try again");
        }
    }

// buddyList.h

#pragma once
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;

class buddy {
friend class buddyList;

public:
    buddy() {
        first = last = phone = ""; next = NULL;
        cout << "Buddy allocated\n";
    }

~buddy() { 
    if (next != NULL) {
        delete next;
        cout << "Buddy " << first << " " << last << " deallocated!\n";
    }
}

void set(string fname, string lname, string tele) {
    first = fname;
    last = lname;
    phone = tele;
}
void print() {
    cout << left << setw(15) << last << setw(15) << first << "  " << phone << endl;
}
private:
    string first;
    string last;
    string phone;
    buddy * next;   
};

// buddyList.cpp

#pragma once
#include <string>
#include "buddy.h"
using namespace std;

class buddyList {
public:
    buddyList();
    ~buddyList();
    void add(string fname, string lname, string phone);
    void print();
    int drop(string fname, string lname);
    void sort();
    void read();
private:
    buddy * head;
    buddy* search(string fname, string lname);
    buddy* maxByName();
    void remove(buddy * r);
    void add(buddy * n);
};

}

1 个答案:

答案 0 :(得分:2)

堆栈溢出通常是由递归疯狂引起的。通过这种方式,我的意思是您正在执行某种递归操作,例如delete-在当前元素的析构函数中对下一个(列表中的)元素进行操作,但是由于某些原因,列表的完整性受到损害。 / p>

由于您的buddy类仅包含有关列表中元素的信息,因此您可能应该查看列表代码本身。这在行中非常诱人:

friend class buddyList;

对于析构函数而言,首先清除其“拥有”的所有项(例如列表的其余部分)没有任何问题,但您必须正确地进行操作。从您提供的代码来看,看起来还可以,但是一切都基于buddyList正常工作的事实。


事实上,现在您已经添加了一些buddyList代码,这似乎是确切的问题。查看添加项目的代码:

buddy * b = new buddy;
b->first = fname;
b->last = lname;
b->phone = phone;
add(b);
delete b;          // Hmm!!

您在这里遇到了严重的问题。您分配了一个新的伙伴,将指向它的指针添加到列表中,然后释放它所引用的内存。例如,如果内存被其他地方重用(例如列表中的另一个节点)而仍被列表引用,那将不会很好地结束。


所以,这就是我的建议。

  1. 正确区分职责。给定的节点永远不必与列表中的其他节点相关。列表本身应该负责清理自己。

  2. 请勿使用递归进行清理。递归的理想用例是快速减少问题空间。例如,在二进制搜索中,您在每个递归级别上都删除了剩余问题空间的一半。拥有一百万个节点的列表,每级删除一个节点,几乎可以肯定的是,您的堆栈会溢出一百万个单独的帧。

  3. 如果您不使用C ++智能指针(a),请学习如何遵循所有权流程,不要将一个对象“交给”其他对象,然后立即执行它不可用:-)


例如,这是一个实现,在仍然使用原始指针的情况下,解决了上面的前两点:

#include <iostream>
#include <memory>

class Node {
public:
    Node(const std::string &str): m_str(str), m_next(nullptr) {}

private:
    friend class NodeList;
    std::string m_str;
    Node *m_next;
};

class NodeList {
public:
    NodeList(): m_head(nullptr), m_tail(nullptr) {};
    ~NodeList() { clear(); }

    void print() {
        Node *node = m_head;
        std::cout << "List:";
        while (node != nullptr) {
            std::cout << " " << node->m_str;
            node = node->m_next;
        }
        std::cout << "\n";
    }

    void add(const std::string &str) {
        auto newNode = new Node(str);
        if (m_head == nullptr) {
            m_head = m_tail = newNode;
        } else {
            m_tail->m_next = newNode;
            m_tail = newNode;
        }
    }

    // List is responsible for cleaning itself up, and
    // it does it iteratively to mimimise chance of
    // stack blowout.

    void clear() {
        while (m_head != nullptr) {
            Node *save = m_head->m_next;
            delete m_head;
            m_head = save;
        }
        m_tail = nullptr;
    }

private:
    Node *m_head, *m_tail;
};

int main() {
    NodeList list;
    list.print();
    list.add("paxdiablo"); list.add("george"); list.add("bob");
    list.print();
    list.clear();
    list.print();
}

按预期,输出为:

List:
List: paxdiablo george bob
List:

(a)如今在非常的少数情况下,您应该使用newdelete关键字。如果您完全理解并控制对象的所有权,就可以了,但是,如果有任何疑问,现代C ++会提供智能指针来简化对象的管理。