这是一个简单程序的代码,它应该读取每行包含一个单词的文本文件,动态分配存储所有单词所需的内存,将它们打印在屏幕上并释放所使用的内存。
#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的调试器并在该行上设置断点并告诉它在每个断点上继续,程序将正常终止。
由于这是一个非常简单的程序,我希望有一些简单的答案或修复!
答案 0 :(得分:7)
Dict
类具有动态分配的成员,但使用默认的复制构造函数和赋值运算符,当{Dict
副本指向同一个words
数组时1}},当使用Dict
函数时发生。当其中一个loadDict()
实例被破坏时,它会使另一个Dict
实例留下悬空指针,并导致Dict
数组及其元素的双重删除。
如果这不是学习练习,请使用std::vector<std::string>
代替C ++流。例如:
words
答案 1 :(得分:3)
你没有遵守三条规则:
http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
Dict r
在loadDict
结束时被破坏,而其自身的浅层副本则返回main
。在main
结束时,指针再次为delete
。
通常在C ++中,你不需要指针。将std::vector<std::string>
存储在Dict
中,不会有任何技巧。
答案 2 :(得分:1)
绝对错误的是您的代码没有复制构造函数,并且您按值返回对象。这可能导致双重破坏,从而双重删除日期。是否发生这种情况取决于复制结构是否被忽略。
此外,您为每个字符串分配足够的字符来保存字符串而不是空终止符。也就是说,要存储长度为s
的字符串strlen(s)
,您需要分配strlen(s) + 1
个字符。
我建议使用std::vector<std::string>
代替:这可以避免大多数问题。
答案 3 :(得分:0)
您的代码中存在一些问题:
您没有检查fopen是否返回有效指针。 (我得到了这个因为我尝试运行不带txt文件的代码)
您正在返回一个Dict对象,它会调用复制构造函数而您没有定义它。
您为Dict使用了一个赋值操作符,但没有定义一个。
您可以尝试更改loadDict()以返回一个size数组,然后将该数组传递给Dict构造函数。这样,您就不必编写复制构造函数和赋值操作符。