-3

文字列とベクトルの代わりに、動的に割り当てられた 2 次元の char 配列を使用する必要があるプログラミングの課題があります。char 配列へのポインターを保持する Word と、Word 配列へのポインターを保持する WordList の 2 つのクラスがあります。

セグメンテーション違反は、コードの次のセクションから発生します。

for(int i=0; i<listLength; i++)
    fout << "Word " << i << (wordList[i])->getWord() << endl;

ここで、fout は ofstream オブジェクト、wordList は Word** オブジェクト、getWord() は Word オブジェクトのメンバー関数です。問題は、WordList の別のメンバー関数で同じ wordList[i]->getWord() 構文を使用して、適切な出力を取得することです。

問題を適切に診断するためにさらにコードが必要な場合はお知らせください

より多くのコード:

#include <iostream>
#include <fstream>
#include <cstring>
#include <string>  
#include "Word.h"

using namespace std;

class WordList
{
public:
    int listLength_;
    Word** wordList_; 

WordList()
{   
    char blank = ' ';
    char* blankPtr = &blank;
    setListLength(1);
    wordList_ = new Word* [listLength_];
    for(int i=0; i<listLength_; i++)
    {
        wordList_[i] = new Word(blankPtr);
    }
}

void addWord(Word* word, Word** wordList, int n)
{
    Word** wl_temp = new Word* [n+1];

    for(int i=0; i<n; i++)
    {
        wl_temp[i] = wordList[i];
    }

    wl_temp[n] = word;
    delete[] wordList;
    setWordList(wl_temp);
    listLength_++;            
    cout << " " << (wordList_[n]->getWord()); //works here 
}

void parse(const char* filename)
{
    ifstream fin(filename);

    char end;
    char* tw;
    while(fin >> end)
    {
        fin.unget();
        fin.get(tw=new char[49], 49, ' ');
        Word* w = new Word(tw);
        addWord(w, getWordList(), getListLength());

        delete w;
        delete[] tw;
    }  
}

void output(const char* outfile)
{
    ofstream fout(outfile);

for(int i=1; i<=listLength_; i++)
        fout << "Word " << i << (wordList_[i])->getWord() << endl; //not here
    fout.close();
}
};

int main(int argc, char* argv[])
{
    WordList wordList;

    wordList.parse(argv[1]);
    wordList.output(argv[2]);

    return 1;   
}
4

2 に答える 2

1

WordList::Wordlist

    wordList_[i] = new Word(blankPtr);

ここでは、ローカル変数へのポインタを渡しています。

それ自体が問題であるだけでなく、「文字列」はゼロで終了していません。
オブジェクトの所有権を引き継ぐかどうかに関係なくWord、これにより未定義の動作が発生します。

その引数をコピーする場合Word::Word、これは非常に回りくどい(そして間違った)書き方new Word(" ")です。

parse

    Word* w = new Word(tw);
    addWord(w, getWordList(), getListLength());

    delete w;

w単語リストに追加しました。今、あなたはそれをやっdeleteています。
ワードリストには、解放されたメモリへのポインタが含まれるようになりました。それを逆参照すると、未定義の動作も発生します。

   delete[] tw;

Word::Wordこれは、引数をコピーする場合にのみ問題ありません。それ以外の場合は、何にも使用できないポインタを保持するようになります。

手作業による割り当てとrawポインタを使用する場合は、どのオブジェクトがどのメモリを所有し、その割り当てと解放を担当するかについて、非常に明確なポリシーを設定する必要があります。
これを行うのに最適なタイミングは、キーボードに触れる前です。

于 2013-02-15T11:04:01.927 に答える
0

blankPtrコンストラクターがローカル変数を指している場合、コンストラクターが戻ると、このポインターは無効になることに注意してください。また、parse関数では、文字列へのポインターを削除し、そのポインターも無効にします。それだけでなく、実際にWordオブジェクト ポインターを削除します。つまり、配列に不正なポインターが含まれていることになります。

Wordコンストラクター内でコピーを作成しない限り (ポインターをコピーするだけでなく、新しいメモリを割り当てます) 、Wordオブジェクトには不正なポインターが含まれ、未定義の動作が発生します。

未定義の振る舞いは注意が必要です。

于 2013-02-15T10:50:37.400 に答える