【问题标题】:Why this code works well in Linux but failed in Windows?为什么这段代码在 Linux 中运行良好但在 Windows 中失败?
【发布时间】:2013-03-28 20:48:06
【问题描述】:

我写了一些链表代码: 链表的定义:

struct Node {
    // data is used to store an integer value in this node
    int data;
    // a pointer points to the next node
    Node* link;
    // inializes the node with a 0 value in data and a null pointer in link
    Node() : data(0), link(NULL) {};
    // destructor release space allocated to the linked list
    ~Node() {delete link;}
};

显示链表:

void display_and_count(Node* aLink) {
    cout << "Entries: ";
    int nodeNumber = 0;                         // elements number of linked list
    for(Node* iterator = aLink; iterator->link != NULL; iterator=iterator->link) {
        cout << iterator->data << ", ";
        nodeNumber++;
    }
    cout << "contans " << nodeNumber << " nodes." << endl;
}// end display_and_count

现在我编写了一个函数,根据阈值将一个链表拆分为两个 LESS 和 MORE,并删除原始链表中的节点:

void split_them_up(Node* aLink, Node* less, Node* more, int threshold) {
    Node* lessHead = less;                              // head of less
    Node* moreHead = more;                              // head of more
    bool isThresholdInALink = false;                    // store if threshold is an element of aLink
    for(Node* iterator = aLink; iterator->link != NULL; iterator = iterator->link) {
        if(iterator->data < threshold) {
            less->data = iterator->data;
            less->link = new Node;
            less = less->link;
        }
        else if(iterator->data > threshold) {
            more->data = iterator->data;
            more->link = new Node;
            more = more->link;
        }
        else {
            isThresholdInALink = true;
        }
    } // end for(Node* iterator = aLink; iterator->link != NULL; iterator = iterator->link)

    less = lessHead;
    more = moreHead;

    delete aLink;
    // If threshold is an element of aLink, then the new linked list contains the only threshold.
    // If threshold isn't in aLink, then the new linked list contains nothing
    aLink = new Node;
    if(isThresholdInALink) {
        aLink->data = threshold;
        aLink->link = new Node;
    } // end if(isThresholdInALink)*/
} // end split_them_up

那么这是主要功能:

int main() {
    Node* ENTRIES = new Node;           // define a linked list

    get_input(ENTRIES);
    display_and_count(ENTRIES);

    Node* less = new Node;              // define less list
    Node* more = new Node;              // define more list
    cout << "Enter a threshold: ";
    int thd;                            // threshold
    cin >> thd;
    split_them_up(ENTRIES, less, more, thd);

    cout << "Less list: " << endl;
    display_and_count(less);
    cout << "More list: " << endl;
    display_and_count(more);
    cout << "ENTRIES: " << endl;
    display_and_count(ENTRIES);
}

get_input 函数从用户那里获取一些整数,然后 -1 结束:

void get_input(Node* aLink) {
    Node* head = aLink;                 // head of linked list
    int capacity=1;                     // the capacity of intArray
    int* intArray = new int[capacity];  // an array stores user input
    int size=0;                         // actual number of elements stored in the intArray

    cout << "Input some integers, -1 to end: ";
    while(true) {
        int input;
        cin >> input;
        if(input == -1) break;
        if(!isContained(intArray, size, input)) {
            intArray[size]=input;
            size++;
            // if size meets capacity, double capacity
            if(size >= capacity) {
                int* temp = new int[capacity];
                int oldCapacity = capacity;
                for(int i=0; i < oldCapacity; i++) temp[i]=intArray[i];
                delete[] intArray;
                capacity = 2*capacity;
                intArray = new int[capacity];
                for(int i=0; i < oldCapacity; i++) intArray[i]=temp[i];
                delete[] temp;
            } // end if(size >= capacity)
        } // end if(!contained(intArray, size, input))
    } // end while(true)

    for(int i=0; i<size; i++) {
        aLink->data = intArray[i];
        aLink->link = new Node;
        aLink = aLink->link;
    }
    delete[] intArray;
    aLink = head;
} // end get_input

被包含:

bool isContained(int* array, int aSize, int n) {
    for(int i=0; i<aSize; i++) {
        if(array[i] == n) return true;
    }
    return false;
} // end isContained

在 Linux 系统中执行时一切正常。但是在 Windows 中,它会在 split_them_up 之后在 ENTRIES 中显示一个随机值,并且程序会崩溃,给出“访问冲突读取位置”。

【问题讨论】:

  • 它在哪里崩溃? 如果你不能回答这个问题,你可能自己还没有使用过调试器,不应该在 SO(还)上问这个问题.
  • 主函数最后一行:display_and_count(ENTRIES);
  • 这篇文章的代码太多了,没人会读完。您应该尝试精简它,也许在较小的测试程序中重现您的问题。
  • 您确实意识到传递给split_them_uplessmore 指针是按值传递的,因此使用less = lessHead; 之类的代码分配给它们对于外部调用者来说绝对没有任何意义,对吧?此外,main() 泄露了分配给lessmore 的两个节点。最后,我不建议在包含标准标头的代码中使用 less 作为任何类型的变量名,因为 std::less&lt;&gt; 是库定义的比较器,必然会导致混淆或彻底的错误。
  • 请用g++ -Wall -g编译,改进代码直到没有警告,然后用gdb调试器和valgrind内存泄漏检测器调试代码;你可能有内存问题......程序显然在 Linux 上正确完成的事实并不意味着没有泄漏(或过早的freedelete)或其他一些内存问题。

标签: c++ linux windows crash linked-list


【解决方案1】:

我不知道这是否能解决问题,但我很确定您不希望节点使用这样的析构函数。

  1. 没有新的,所以不需要删除。
  2. 如果列表中的某个节点触发删除下一个节点、下一个节点、下一个节点...,您将如何实现删除它?

【讨论】:

  • 我在链表中​​有一个析构函数,所以我认为在实现删除时它会调用析构函数,然后调用下一个节点和下一个
  • 这不是列表通常的工作方式。一个节点应该不能作用于其他节点,更不用说删除它们了。它是管理这些东西的节点列表。编辑:由于您没有列表对象,因此您的 main.cpp 将负责删除它创建的节点。
  • 是的,我认为问题可能是这样的。但为什么它在 Linux 中运行良好?
  • 老实说,我不知道。不过,我还没有解析你所有的代码,可能还有更细微的错误我错过了
【解决方案2】:

当然你在操作ENTRIES时会崩溃; split_them_up 函数删除了它指向的 Node 对象。

从外观上看,您打算将 aLink 声明为指针到指针,以便您实际上可以更改 ENTRIES 的值以指向新声明的 Node(此时您是泄漏)。

或者,您可以删除子节点并重用aLink,而不是删除aLink,即替换它:

delete aLink;
aLink = new Node;
if(isThresholdInALink) {
    aLink->data = threshold;
    aLink->link = new Node;
}

用这个:

delete aLink->link;
if(isThresholdInALink) {
    aLink->data = threshold;
    aLink->link = new Node;
} else {
    aLink->data = 0;
    aLink->link = NULL;
}

为什么糟糕的代码可以在 Linux 上运行?猜测一下,新声明的Node恰好与原来删除的节点创建在同一个位置,所以ENTRIES不小心指向了正确的位置。

我还要评论说你不需要lessHeadmoreHead;他们没有做任何有用的事情。完全删除它们。就像aHead 一样,由于lessmore 没有声明为指向指针的指针,调用函数中的值不会受到split_them_up 内部发生的任何事情的影响。

附加:析构函数,

~Node() {delete link;}

如果链接很大,可能会溢出堆栈。递归是一件好事,但在极端情况下就不行了。 :-)

【讨论】:

    猜你喜欢
    • 2020-06-04
    • 2021-08-29
    • 1970-01-01
    • 1970-01-01
    • 2021-03-13
    • 2019-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多