1

これは、1 行に 1 つの単語を含むテキスト ファイルを読み取り、すべての単語を格納するために必要なメモリを動的に割り当て、それらを画面に出力し、使用されているメモリの割り当てを解除する単純なプログラムのコードです。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

class Dict {
 public:
 int size;
 char ** words;
 Dict (int, int*);
 ~Dict ();
};

Dict::Dict(int s,int* sizes) {
 int i;
 size=s;
 words = new char* [s];
 for (i=0;i<s;i++)
  words[i] = new char [sizes[i]];
}

Dict::~Dict() {
 int i;
 for (i=0;i<size;i++) {
  delete [] words[i];
  printf("i=%d\n",i); // for debugging
  }
 delete [] words;
}

Dict loadDict (char* filename) {
 FILE* file;
 int n=0,i=0;
 int * sizes;
 char buff [64];

 file=fopen(filename,"r");
 while (!feof(file)) {
  n++;
  fscanf(file,"%*[^\n] \n");
 }
 sizes=new int [n];

 rewind(file);
 while (!feof(file)) {
  if (fscanf(file,"%s\n",buff)>0) {
   sizes[i]=strlen(buff);
   i++;
  }
 }

 rewind(file);
 Dict r(n,sizes);
 i=0;
 while (!feof(file)) {
  fscanf(file,"%s\n",r.words[i]);
  i++;
 }

 delete [] sizes;
 return r;
}

int main() {
 int i;
 Dict d=loadDict("dict.txt");
 for (i=0;i<d.size;i++)
 printf("%s|\n",d.words[i]);
 printf("%d DONE.\n",d.size);
 return 0;
}

割り当て解除は Dict クラスのデストラクタで行われます。ただし、ほんの数単語のサンプル テキスト ファイルで使用すると、単語は正しく出力されますが、フォームの 3 行の実行後に を呼び出すと~Dictアプリケーションがクラッシュしますdelete [] words[i];。Code::Block のデバッガーを使用してその行にブレークポイントを設定し、各ブレークポイントで続行するように指示すると、プログラムは正常に終了します。

これは本当に単純なプログラムなので、何らかの簡単な答えや修正があることを願っています!

4

4 に答える 4

7

Dictクラスは動的に割り当てられたメンバーを持っていますが、デフォルトのコピー コンストラクターと代入演算子を使用しているため、コピーが作成されると、同じ配列を指す 2 つのインスタンスが発生しDictます。これは、関数の使用時に発生します。インスタンスの 1 つが破棄されると、他のインスタンスはダングリング ポインターのままになり、配列とその要素が二重に削除されます。wordsDictloadDict()DictDictwords

3 のルールとは何ですか? を参照してください。

これが学習課題でない場合は、std::vector<std::string>代わりに C++ ストリームと共に を使用してください。例えば:

std::vector<std::string> words;
...

std::ifstream in(filename);
std::string line;
while (in >> line) words.push_back(line);
于 2012-11-26T22:35:06.170 に答える
3

あなたは3つのルールに従っていません:

http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29

Dict rloadDict自分自身の浅いコピーが に返されたときに、 は の最後に破棄されmainます。mainポインターの最後には、delete再び d があります。

C++ ではよくあることですが、ここではポインターは必要ありません。に格納するstd::vector<std::string>Dict、トリックはありません。

于 2012-11-26T22:35:00.383 に答える
1

間違いなく間違っているのは、コードにコピーコンストラクターがなく、値でオブジェクトを返していることです。これは二重の破壊につながる可能性があり、したがって、日付の二重の削除につながる可能性があります。これが発生するかどうかは、コピーの作成が省略されるかどうかによって異なります。

さらに、文字列を保持するのに十分な文字を各文字列に割り当てますが、ヌルターミネータは割り当てません。つまり、s長さのある文字列を格納するには、文字strlen(s)を割り当てる必要がありますstrlen(s) + 1

代わりに使用することをお勧めしstd::vector<std::string>ます。これにより、ほとんどの問題が回避されます。

于 2012-11-26T22:42:12.993 に答える
0

あなたのコードにはいくつかの問題があります:

  1. fopen が有効なポインターを返すかどうかを確認していません。(txtファイルなしでコードを実行しようとしたので、これを取得しました)

  2. コピー コンストラクターを呼び出す Dict オブジェクトを返していますが、定義していません。

  3. Dict の代入演算子を使用しましたが、定義していません。

サイズの配列を返すように loadDict() を変更してから、その配列を Dict コンストラクターに渡すことができます。この方法では、コピー コンストラクターと代入演算子を記述する必要はありません。

于 2012-11-26T22:55:29.517 に答える