令人沮丧的指针错误

时间:2014-04-19 01:22:06

标签: c++

对于我的生活,我无法弄清楚出了什么问题。我知道错误发生在下面标记为displayQueue的函数中,但所有语法和逻辑似乎都是正确的。

Visual Studio给出了错误:“ex11_1.exe中0x00215A86处的未处理异常:0xC0000005:访问冲突读取位置0xCDCDCDE1。”但实际上,我不知道这是指......

#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;

struct QueueNode {
    string data;
    QueueNode *link;
};
typedef QueueNode* QueueNodePtr;


class Queue {
public:
    // Constructors/Destructor.
    Queue();
    Queue(const Queue& aQueue);

    // Accessors.
    bool empty() const;
    void displayQueue ();

    // Mutators.
    void add(string item);
    string remove();    // This should probably be replaced with pop and top - especially for displayQueue... empty() in functions can be replaced with count == 0. Yes, I will do this.

private:
    QueueNodePtr front;     // Points to head of linked-list queue.
    QueueNodePtr back;      // Points to tail of linked-list queue.
    size_t count;
};

int main () {
    Queue myQueue;

    myQueue.add("abc");
    myQueue.add("def");
    myQueue.add("ghi");

    myQueue.displayQueue();     // The error is here somewhere. abc is printed and but nothing else.

    system("pause");
    return 0;
}

Queue::Queue() {
    front = NULL;
    back = NULL;
    count = 0;
}

Queue::Queue(const Queue& aQueue) {
    front = aQueue.front;
    back = aQueue.back;
    count = aQueue.count;
}

bool Queue::empty() const {
    if (count == 0) {
        return 1;
    } else {
        return 0;
    }
}

void Queue::displayQueue () {
    // There is a problem here somewhere...

    QueueNodePtr here = front;
    for (int i = 0; i < count; i++) {
        cout << here->data << endl;
        here = here->link;      
    }
}

void Queue::add(string item) {
    QueueNodePtr newNode;
    newNode = new QueueNode;

    if (count == 0) {
        // If inserted in an empty queue, back and front point to same element.
        newNode->data = item;
        // newNode->link = NULL;    // Not sure this part is even necessary.
        back = newNode;
        front = back;
    } else {
        // Otherwise, leave front pointer where it's at.
        newNode->data = item;
        newNode->link = back->link;
        back = newNode;
    }
    count ++;
}

string Queue::remove() {
    string returnString;

    if (count == 0) {
        return returnString;
    } else if (count == 1) {
        returnString = front->data;
        front = NULL;
        back = front;
        count--;
        return returnString;
    } else {
        returnString = front->data;
        front = front->link;
        count--;
        return returnString;
    }
}

编辑:如果有人可以给我任何关于使用调试器来解决这类问题的提示,或者给我一个可以解释这个问题的链接,我将不胜感激。

2 个答案:

答案 0 :(得分:4)

错误就在这一行,但为了学习,我不会给出正确的版本,只是提示一些:

newNode->link = back->link;

在执行此代码时,back指向哪个节点?它的link指向什么?您需要修改哪个节点link

至于自己找到这个,你可以使用调试器找出导致崩溃的行;这表明link值存在问题。

P.S。您的复制构造函数实际上并不复制链接列表;它只是创建一个指向同一链表的新Queue对象,因此如果您向副本添加一个元素,它将显示在原始队列中。

答案 1 :(得分:2)

地址0xCDCDCDCD的访问冲突意味着您的程序从未初始化的存储中加载了一个指针,然后取消引用它。 Microsoft的调试分配器将此模式用于新分配的未初始化存储,并在合适的编译模式下,也用于堆栈位置。如果将此未初始化的存储视为指针变量,则该指针中的模式可识别。而且,它几乎肯定是一个无效的指针,会触发异常。所以好处是快速捕获无效指针的使用,并且该模式告诉您原因很可能是未初始化的存储(尽管这不是100%结论)。

例如:

struct contains_pointer { char *str; } *ptr = malloc(sizeof *ptr);

strcpy(ptr->str, "abc"); // ptr->str is uninitialized

或者:

int *pint;
*pint = 0;  // pint is uninitialized

让编译器和库用像CDCDCD这样的模式覆盖未初始化的存储...可能非常有用。你应该用调试器确定崩溃的位置,然后从那里开始向后工作:指针值的起源在哪里以及为什么它没有被初始化。

(指向地址CDCDCDCD的错误指针可能会导致其他方式:纯粹的侥幸(不太可能)或免费使用后的错误:程序释放一些内存但继续保持指向它的指针,而不使用它然后,将内存重新分配给程序的其他部分,并标记为未初始化,并且偶然地,指针的原始用户使用它,从内存加载指针值。此时, CDCDCDCD指针结果,所以它看起来像一个use-before-init错误,实际上它是一个免费使用后的bug。基于&#34;内存中毒&#34;模式的调试不准确!)< / p>