0

配列ベースのリストのプログラムには、次の3回を呼び出す関数があります。

list->remove(1)

私の問題は、これが印刷されると、次の新しい最初のアイテムに移動するのではなく、元の最初のアイテムを3回削除すると表示されることです。

具体的には、このコードが呼び出されたときtest.cpp

for (int i = 1; i <= 3 && ! list->isEmpty(); i++) {
        cout << "Deleting item " << i << "." << endl;
        try {
                cout << "Deleted item " << list->remove(1) << endl;
        }
        catch (int e) {
                cout << "*** Error deleting from position " << i << " ***" << endl;
        }
}

次を返します。

アイテムの削除1.
アイテムの削除1アイテムの
削除2.
アイテムの削除1アイテムの
削除3.
アイテムの削除1

これが私が作成したABListクラスです。エラーは私のremoveメソッドにあると思いますが、どこにあるのかわかりません:

#ifndef _ABLIST_H_
#define _ABLIST_H_

#define LIST_MAX 10

#include <iostream>
#include "ABCList.hpp"

using namespace std;

template <class T>
class ABList : public ABCList<T> {

    private:
        T    a[LIST_MAX];
        int  size;

    public:
        ABList ();
        ~ABList ();
        virtual bool isEmpty ();
        virtual int  getLength ();
        virtual void insert (int pos, T item);
        virtual T    remove (int pos);
        virtual T    retrieve (int pos);
};


template <class T>
ABList<T>::ABList () {
    size = 0;
}

template <class T>
bool ABList<T>::isEmpty () {
    if (size == 0)
        return true;
    return false;
}

// returns size, which is updated whenever the list is lengthened or shortened
template <class T>
int ABList<T>::getLength() {
    return size;
}

template <class T>
void ABList<T>::insert(int pos, T item) {

    try {
        // if list is at maximum size
        if (size >= LIST_MAX)
            throw "Size is greater than or equal to LIST_MAX\n";
        // if "pos" is a negative number
        if (pos < 0)
            throw "Pos must be greater than 0\n";
        // if "pos" is outside the bounds of the existing list
        if (pos > size + 1)
            throw "Pos must be less than or equal to list size\n";

        //shift all items at indices > pos one index up
        for (int i = size; i >= pos; --i) {
            a[i] = a[i-1];
        }
        //insert new item
        a[pos-1] = item;
        //increment size
        size++;

    } catch (char* message) {
        cout << "Error: " << message;
        throw 1; // any int will do, to catch exception flag in test.cpp
    }
}

template <class T>
T ABList<T>::remove(int pos) {

    try {
        if (pos < 1)
            throw "Pos cannot be less than 1";
        if (pos > size)
            throw "Pos cannot be greater than size";
        //find T to be removed, to return later
        T temp = retrieve(pos);
        //shift all items greater than pos down one index
        for (int i = pos + 1; i <= size; i++)
            a[i] = a[i+1];
        // decrement size
        size--;
        return temp;
    } catch (char* message) {
        cout << "Error: " << message;
        throw 1;
    }
}

template <class T>
T ABList<T>::retrieve(int pos) {
    try {
        //check that pos is valid
        if (pos < 1 || pos > size)
            throw "Position is outside bounds of ABList\n";

        return a[pos-1];

    } catch (char* message) {
        cout << "Error: " << message;
    }
}


#endif

これがメインプログラムです。(この問題のために、私はそれが不変であると仮定する必要があります):

int main () {
    // Testing the List implmenetations; first, get a list:
    ABCList<string> * list = getList();

    // Test "insert"
    cout << "Let's populate the list with a few items." << endl;
    for (int i = 1; i <= TEST_SIZE; i++) {
        int pos = getPos(i); // Randomise "i" to test
        string input;

        cout << "Enter a word to place into the list at position " << pos << ": ";
        cin >> input;

        try {
            list->insert(pos, input);
            cout << "Successfully inserted at position " << pos << "." << endl;
        }
        catch (int e) {
            cout << "*** Error inserting at position " << pos << " ***" << endl;
        }
}


    // Test "retrieve" & "getLength"
    cout << "List is as follows: \n\t";
    for (int i = 1; i <= list->getLength(); i++) {
        cout << list->retrieve(i) << " ";
    }
    cout << endl;


    // Test "delete" and "isEmpty"
    for (int i = 1; i <= 3 && ! list->isEmpty(); i++) {
        cout << "Deleting item " << i << "." << endl;
        try {
            cout << "Deleted item " << list->remove(1) << endl;
        }
        catch (int e) {
            cout << "*** Error deleting from position " << i << " ***" << endl;
        }
    }

    // Done. Let the destructor handle the rest.
    delete list;

    return 0;
}
4

2 に答える 2

2

削除中は、でアイテムを取得した後にこれを行います(1)(これは実際には次のアイテムa[0]です:

for (int i = pos + 1; i <= size; i++)
    a[i] = a[i+1];

さてpos、これが入力されたときは何ですか?ですので(1)、リストをから(2)に移動しsize、すべてをからにシフトし3..(size+1)ます2...(size)。「位置」1のアイテム(これも実際に0は配列のスロットにあり、上書きされることはないため、常に報告された戻りアイテムです。

これは正しくないだけでなく、アレイが完全に実装されている場合はUB(未定義動作)でもあり、最後の実行可能な場所の1スロット先のデータにアクセスします。

あなたは1ベースのアイテムを捨てたいと思っていposます(あなたのデザインであり、私のものではありません)。その基礎となる要素はa[pos-1]、配列内の場所にありました。だからこれを試してみてください:

for (int i = pos; i < size; ++i)
    a[i-1] = a[i];

これpos、常に1以上であることを確認する場合は安全です(実際、これを実行しているように見えます)。個人的にはゼロベースのインデックスシステムを使い続けますが、設計上の理由があると思います。

于 2012-12-24T19:42:02.953 に答える
1

removeメソッドでは、1つのインデックスを誤ってシフトダウンしています。次のようになります。

for (int i = pos + 1; i <= size; i++)
    a[i-1] = a[i]; // instead of a[i] = a[i+1];

他の方法は

for (int i = pos; i <= size; i++)
    a[i] = a[i+1];

動作するか確認してください。

于 2012-12-24T19:46:50.777 に答える