1. ホーム
  2. c++

[解決済み] c++ 解放されるポインタが割り当てられていないエラー

2022-02-18 12:13:01

質問内容

c++のnew/delete、hashfunction、linkedを練習しています。

自分で練習してみました。

という構造体を持っています。

typedef struct student
{
    int id;
    string fName;
    string lName;
    student * nextStudent;
}Student; 

そして、main関数でstudentの配列を定義しています。

Student * table = new Student [10];

私は、IDを受け取り、0-9に変更する独自のハッシュ関数を持っています。 私は学生を追加したい私は次のようになります。

void addStudent(int studentId, string firstName, string lastName, Student  *table)
{
    // using hash function, convert the id into hashed id
    int hashedID = hashFunction( studentId );   

        Student * pointer = &table[hashedID];

        while(pointer->nextStudent !=NULL){
            pointer = pointer->nextStudent;
        }

        // once we reach to the student who has NULL in nextStudent
        // add student
        Student *tmp = new Student;
        tmp->id = studentId;
        tmp->fName = firstName;
        tmp->lName = lastName;
        tmp->nextStudent = NULL;

        // link
        pointer->nextStudent = tmp;

}

テストしてみましたが、問題ないようです。

問題は削除です。 生徒の変数は動的メモリに保存されているので deleteを使う必要があります。

以下は、私のコードです。

void deleteAll(Student *table, int len)
{
    for (int i = 0; i < len; i++)
    {
        Student* tmp = &table[i];

        // delete student info except the last one
        while ( tmp -> nextStudent !=NULL){
            Student* tmp2;
            tmp2 = tmp;
            tmp = tmp->nextStudent;
            delete tmp2;
         }
    }
}

すべての生徒のヴァリアルを訪問し、削除を実行しました。 私の削除機能には何の問題もありません...

これが、実行後の結果です。

malloc: *** error for object 0x7f85f1404b18: pointer being freed was not allocated

何が間違っていたのか、さっぱりわかりません。 助けていただけますか?

EDIT...

皆さんから頂いたご意見の通り メイン関数に "delete [] table" を追加しました。 また、deleteAll関数の中の"delete tmp"を削除し、"delete [] table"で対応できると考えています。

それでもうまくいきません。

ところで、最初の投稿でinitTable関数を追加するのを忘れていました。 initTableはテーブルを初期化する関数です。

void initTable (Student *table, int len)
{
    for (int i = 0; i < len; ++i)
    {
        table[i].nextStudent = NULL;
    }
}

ありがとうございました。

解決方法は?

その nextStudent フィールドは初期化されないので、ここで作成された10個の要素はすべて未知の値を指しています。

Student * table = new Student [10];

これにより addStudent をループさせる。 pointer->nextStudent が偶然 NULL 値に当たった場合、所有しないメモリを上書きします (最初の反復処理で幸運にも NULL に当たった場合を除く)。

while(pointer->nextStudent !=NULL) { ... }

student` 構造体 (なぜ typedef なのか?) には、少なくともこれを行うためのコンストラクタが必要です。

student::student() : nextStudent(NULL) { }


[ EDIT ]です。 もう一つの問題は、@JonathanPotter がコメントで適切に指摘してくれたように、10 個のそれぞれの先頭が student リストが table 配列になります。それは ではない 動的に割り当てる必要があります。 ない を個別に削除することができます。

簡単な修正方法としては student デストラクタで子ノードを再帰的に削除します。

student::~student() { if(nextStudent) delete nextStudent; }

次に deleteAll に還元される。

void deleteAll(student *table, int len)
{
    for (int i = 0; i < len; i++)
    {
        student *tmp = &table[i];
        if(tmp->nextStudent) delete tmp->nextStudent;
    }
    // this leaves the dynamically allocated table[] in place
    // to delete it as well, just `delete [] table;`
}

しかし、リストが大きくなると、このような再帰は実行不可能になるので、(再帰的なデストラクタを含まない)イテレーションに書き換えるのがよいでしょう。

student::~student() { }

// ...

void deleteAll(student *table, int len)
{
    for(int i = 0; i < len; i++)
    {
        student *tmp = &table[i];

        // delete student info except the *first* one
        for(student *tmp2; tmp2 = tmp->nextStudent; )
        {
            tmp->nextStudent = tmp2->nextStudent;
            delete tmp2;
        }
    }
    // this leaves the dynamically allocated table[] in place
    // to delete it as well, just `delete [] table;`
}