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 类的析构函数中完成的。但是,在仅包含几个单词的示例文本文件上使用这些单词时,这些单词可以正确打印,但是在~Dict执行 3 行表单后调用会导致应用程序崩溃delete [] words[i];。如果我使用 Code::Block 的调试器并在该行上设置一个断点并告诉它在每个断点上继续,程序将正常终止。

由于这是一个非常简单的程序,我希望有一些简单的答案或修复!

4

4 回答 4

7

该类Dict具有动态分配的成员,但使用默认的复制构造函数和赋值运算符,这会导致在制作副本时Dict指向同一个words数组的两个实例,这在使用函数Dict时会发生。loadDict()当其中一个Dict实例被破坏时,它会为另一个实例留下Dict一个悬空指针,并将导致words数组及其元素的双重删除。

请参阅什么是三法则?

如果这不是学习练习,请使用 astd::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

您没有遵循三原则:

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

Dict r在结束时被破坏,loadDict同时将自身的浅拷贝返回到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 回答