为什么最后一个拆分函数会导致分割故障?如何解决此问题

Why the last SPLIT function causes SEGMENTATION FAULT? How to fix this

本文关键字:何解决 解决 问题 故障 函数 拆分 最后一个 分割 为什么      更新时间:2023-10-16

我在圆形缓冲区中编写了双连锁列表的典型程序(此处:ring(。我正在使用迭代器(我必须,学校项目(。

似乎都起作用了,但是记忆中有一些东西,我找不到以某种方式修复它的方法。分割故障的原因可能是我正在访问"禁止"部分。

整个代码在这里

问题是我找不到应该修复的地方。

功能拆分:从原始的圆形缓冲液制成了两个单独的圆形缓冲液。

对于第一个,我从第一位置开始迭代,第二个位置的第二个位置。dir表示顺时针(如果为true(,则为false。LEN是指我们要获得的环的长度。我们迭代每个第二个元素。

在剪切代码中,您得到了真实的例子。

/******* external function ********/
/****** Example of the split function:
split (r3,r1,true,3,r2,false,6)
r3= 1,2,3,4,5
r1= 1,3,5
r2= 2,5,3,1,4,2
********/
template <typename Key>
Ring<Key> split(const Ring<Key> &source,Ring<Key> &result1, bool dir1, int len1, Ring<Key> &result2, bool dir2, int len2){
typename Ring<Key>::iterator i1 = source.begin();
typename Ring<Key>::iterator i2 = source.begin();
/*I moved second iterator to the 2nd position in original Ring*/
i2++;

if (source.isEmpty()){
    cout<<"Empty source Ring"<<endl;}
if (source.length()==1||source.length()==2){
    return source;
        }
if((len1 <= 0) || (len2 <= 0))
{
    cout << "split():(incorrect lengths)" << endl;
}
    if(!i1.isNULL()){
        for(int i = 0; i < len1; i++)
        {
            result1.insertLast(i1.getKey());
            if(dir1){
                i1++;
                i1++;;
                }
            else
                {i1--;
                i1--;
                }}}
cout<<result1;
    if(!i2.isNULL()){
        for(int i = 0; i < len2; i++)
        {
            result2.insertLast(i2.getKey());
           if(dir2){
                i2++;
                i2++;
                }
            else
                {i2--;
                i2--;
                }}}
cout<<result2;}

i在这里分配您的代码:https://ideone.com/7af6d7

纠正了一些位。看来它不再是segfault,但是我不知道它可以做您期望的事情。阅读评论的注释。您还应指定您是使用C 11或更大的或旧的C 代码(很抱歉,如果是这样(

至少应以警告形式捕获这一点(您应该使用-Werror标志编译(。

另外,请正确缩进您的代码。

无论如何,我不知道为什么您要返回拆分函数上的整个源的副本(它应该返回错误或 bool中的 voidthrow(。

#include <iostream>
#include <stdlib.h>
using namespace std;
template <typename Key>
class Ring
{
    struct Node
    {
        Key key;
        Node *next= nullptr; // Always initialize. Worst case if you do it 
                             // twice: the compiler will be smart enough to 
                             // remove one of the occurrences
        Node *prev= nullptr; // Ditto
    };
    Node *any= nullptr; // Use nullptr on C++11 and onwards
    // Also, any is not a very good name, prefer using root or first
public:
/******* iterator class methods definitions ********/
    class iterator
    {
        Node *el= nullptr; // Ditto
    public:
        iterator()= default; // or iterator() {}
        ~iterator()= default; // or ~iterator() {}
        constexpr iterator(const iterator& copyIter)
        : el(copyIter.el)
        {
            // Empty constructor gets to be constexpr
            // Improves optimizing and can be evaluated at runtime
        }
        constexpr iterator(Node *copyEl)
        : el(copyEl)
        {
        }
        iterator &operator = (const iterator &copyIter)
        {
            el = copyIter.el;
            return *this;
        }
        bool operator == (const iterator &comp) const
        {
            return el == comp.el;
        }
        bool operator != (const iterator &comp) const
        {
            return el != comp.el;
        }
        /* I don't think this operator is good practice
        iterator operator + (const unsigned int number) const
        {
            iterator new_iter = *this; // Could be auto new_iter = *this in C++11
            for(int i = 0; i < number; i++) { // Style: Always put brackets
                new_iter++;
            }
            return new_iter;
        }*/
        iterator& operator ++ ()
        {
            if (el) {
                el = el->next;
            }
            return *this;
            // You had no return if it's null
            // Also, no need for != nullptr or != NULL
            // Usually, you return a reference to self
        }
        iterator operator ++ (int)
        {
            iterator copy_iter(el);
            if (el) {
                el = el->next;
            }
            return copy_iter; // You return the copy, no matter what
        }
        /* Ditto
        iterator operator - (const unsigned int number) const
        {
            iterator new_iter = *this;
            for(int i = 0; i < number; i++) {
                new_iter--;
            }
            return new_iter;
        }*/
        iterator& operator --()
        {
            if (el) {
                el = el->prev;
            }
            return *this;
        }
        iterator operator -- (int)
        {
            iterator copy_iter(el);
            if (el) {
                el= el->prev;
            }
            return copy_iter;
        }
        Key getKey() const
        {
            if (el) {
                return el->key;
            }
            cerr << "getKey(): (iterator = NULL)" << endl;
            return Key(); // Empty element, might aswell throw here
        }
        bool isNULL() const
        {
            return !el;
        }
        operator bool() const
        {
            return !isNULL();
        }
    };
/******* methods ********/
    Ring();
    ~Ring();
    Ring(const Ring<Key> &Ring);
    friend ostream &operator << (ostream &o, const Ring<Key> &Ring){Ring.print(); return o;};
    bool operator ==(const Ring<Key> &Ring);
    bool operator != (const Ring<Key> &Ring);
    Ring<Key> &operator = (const Ring<Key> &Ring);
    Ring<Key> operator + (const Ring<Key> &second)const;
    Ring<Key> operator - (const Ring<Key> &second)const;
    bool insertFront(const Key &key);
    bool insertLast(const Key &key);
    bool insertAt(int pos, const Key &key);
    bool insertAfter(const Key &where, const Key &key);
    bool popByKey(const Key &key);
    bool popLast();
    bool popFront();
    bool ifExists(const Key &key);
    bool isEmpty()const;
    int length()const;
    void print()const;
    bool clear();
    void reverse();
/******* additional iterators definitions *******/
    iterator begin() const
    {
        return iterator(any);
    }
    iterator end() const
    {
        return iterator(any? any->prev : nullptr); // Always check before dereference
    }
};
/******* methods definitions ********/
template <typename Key>
Ring<Key>::Ring()
// : any(nullptr) // Prefer initializers. No need anyway because we did any= nullptr
{
    cout << "Constructor: (Empty Ring created)" << endl;
}
template <typename Key>
Ring<Key>::~Ring()
{
    if (!any) {
        cout << "Destructor: ( Ring deleted )" << endl;
    }
    Node *curr = any; // auto
    if (curr) {
        while(any) {
            this->popLast();
        }
        cout << "Destructor: ( Ring deleted )" << endl;
    }
}
template <typename Key>
Ring<Key>::Ring(const Ring<Key> &ring) // Please be consistent. If you're using 
// capital letters for classes, dont call the variable Ring; it should be ring
// : any(nullptr) // Prefer initializers. No need anyway because we did any= nullptr
{
    if (ring.any) {
        Node *curr = ring.any;
        do {
            this->insertLast(curr->key);
            curr = curr->next;
        } while(curr != ring.any);
    }
}
template <typename Key>
bool Ring<Key>::popLast()
{
    if (!any) {
        return true;
    }
    Node *curr = any;
    if (curr->next == curr) { // one Node
        any = NULL;
        delete curr; // Here is where you "hope" no one copied your class
                     // because you're deleting a pointer that other might be
                     // using, that's what's called a dangling pointer
        return true;
    }
    if(curr->next->next == curr) // two Nodes
    {
        Node *temp = curr->next;
        curr->next = curr;
        curr->prev = curr;
        delete temp;
        return true;
    }
    do
    {
        if(curr->next->next == any) // Last Node
        {
            Node *temp = curr->next;
            temp->next->prev = curr;
            curr->next = temp->next;
            delete temp;
            return true;
        }
        curr = curr->next;
    }
    while(curr != any);
    return false;
}
template <typename Key>
bool Ring<Key>::insertFront(const Key &key)
{
    Node *newNode = new Node; // Either way
    newNode->key = key; // Always set the key
    if (!any) { // Empty
        newNode->next = newNode;
        newNode->prev = newNode;
        any = newNode;
    } else {
        newNode->next= any; // Will be always before the "any"
        newNode->prev= any->prev; // Will always steal any's previous
        any->prev= newNode;  // Any will always point at newNode as previous
        any= newNode; // I'm the captain now
        // Actually, for the above, We don't care if it's only one or more      
    }
    return true;
}
template <typename Key>
bool Ring<Key>::operator == (const Ring<Key> &ring)
{
    if (this->isEmpty() && ring.isEmpty()) {
        return true;
    }
    if (this->length() != ring.length()) {
        return false;
    }
    Node *curr1 = this->any;
    Node *curr2 = ring.any;
    do {
        if (curr1->key != curr2->key) {
            return false;
        }
        curr1 = curr1->next;
        curr2 = curr2->next;
        // No null check needed for non empty rings
    } while(curr1 != this->any);
    return true;
}
template <typename Key>
bool Ring<Key>::insertLast(const Key &key)
{
    if (!any) {  // no elements
        this->insertFront(key);
        return true;
    }
    Node *newNode = new Node;
    newNode->key = key;
    newNode->next = any;
    Node* curr = any;
    do {
        if (curr->next == any) {
            newNode->prev = curr;
            any->prev = newNode;
            curr->next = newNode;
            return true;
        }
        curr= curr->next;
    } while(curr != any);
    return false;
}
template<typename Key>
bool Ring<Key>::isEmpty() const
{
    // return !any;
    if (!any) {
        cout << "isEmpty(): (Ring empty)" << endl;
        return true;
    }
    return false;
}
template <typename Key>
int Ring<Key>::length() const
{
    int count = 0;
    Node *curr = any;
    if (!curr) {
        return count;
    }
    do {
        count++;
        curr = curr->next;
    } while(curr != any);
    return count;
}
template<typename Key>
void Ring<Key>::print() const
{
    Node * curr = any;
    if(!curr) {
        cout << "print(): (Ring empty)" << endl;
        return;
    }
    do {
        cout << "t(" << curr->key<< ")";
        curr = curr->next;
    } while(curr != any);
    cout << endl;
}
/******* external function ********/
/****** Example of the split function:
split (r3,r1,true,3,r2,false,6)
r3= 1,2,3,4,5
r1= 1,3,5
r2= 2,5,3,1,4,2
********/
template <typename Key>
Ring<Key> split(const Ring<Key> &source, Ring<Key> &result1, bool dir1, 
                int len1, Ring<Key> &result2, bool dir2, int len2)
{
    if (source.isEmpty()) {
        cout<<"Empty source Ring"<<endl;
        return source;
    }
    if (source.length()==1 || source.length()==2) {
        return source;
    }
    if (len1 <= 0 || len2 <= 0) {
        cout << "split():(incorrect lengths)" << endl;
        return source;
    }
    auto i1 = source.begin(); // typename Ring<Key>::iterator i1 = source.begin()
    auto i2 = source.begin(); // typename Ring<Key>::iterator 21 = source.begin()
    /* I moved second iterator to the 2nd position in original Ring */
    ++i2; // Prefer ++i to i++
    if (i1) {
        for (int i= 0; i < len1; ++i) {
            result1.insertLast(i1.getKey());
            if(dir1) {
                ++i1;
                ++i1;
            } else {
                --i1;
                --i1;
            }
        }
    }
    cout << result1;
    if (i2) {
        for(int i = 0; i < len2; ++i) {
            result2.insertLast(i2.getKey());
            if(dir2) {
                ++i2;
                ++i2;
            } else {
                --i2;
                --i2;
            }
        }
    }
    cout << result2;
    return source; // You *ALWAYS* need to return a value. 
    // This was causing the SEGFAULT (and others like this might also)
}
int main()
{
    Ring<int> R1,R2,R3,R4,R5;
    R1.insertLast(2);
    R1.insertLast(3);
    R1.insertLast(4);
    R1.insertLast(5);
    R1.insertLast(6);
    R1.insertLast(1);
    R2.insertLast(10);
    R2.insertLast(20);
    R2.insertLast(30);
    R2.insertLast(40);
    R2.insertLast(50);
    R2.insertLast(60);
    R2.insertLast(70);
    cout<<"Split function:"<<endl;
    split(R1,R3,false,3,R4,false,6);
    R5.insertLast(10);
    R5.insertLast(20);
    R5.insertLast(30);
    R5.insertLast(50);
    R5.insertLast(50);
    R5.insertLast(60);
    R5.insertLast(70);
    R5.print();
    cout << __FILE__ << ':' << __LINE__ << " I'm alive (no segfault)" << endl;
    return 0;
}