这个版本起作用了。我在我的代码中添加了//注释,以便更好地说明我遇到了什么问题。该程序依赖于读取文本文件。以包含标点符号的段落格式。
一个人可以将这个和上面的内容复制到一个文本文件中,然后运行该程序。
// Word.cpp
#define _CRT_SECURE_NO_WARNINGS // disable warnings for strcpy
#define ARRY_SZ 100
#include <iostream>
#include <fstream>
#include "Word.h"
using namespace std;
Word::Word( const char* word )
{
ptr_ = new char[ strlen( word ) + 1 ];
strcpy( ptr_, word );
len_ = strlen( ptr_ );
}
Word::Word( const Word* theObject )
{
ptr_ = theObject->ptr_;
len_ = theObject->len_;
}
Word::~Word()
{
delete [] ptr_;
ptr_ = NULL;
}
char Word::GetFirstLetterLower()
{
// I want to use ptr_ and len_ here
// but the information is gone!
char c = 0;
return c;
}
char* Word::GetWord()
{
for (int x = 0; x < strlen( (char*)ptr_ ); x++)
ptr_[x]; // Results in a crash.
return ptr_;
}// Word.h
const int FILE_PATH_SZ = 512;
class Word
{
private:
char* ptr_;
int len_;
public:
Word( const Word* ); // an appropriate default constructor
Word( const char* );
~Word( );
char GetFirstLetterLower( );
char* GetWord( );
static char fileEntry[ FILE_PATH_SZ ];
};// main.cpp
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <iostream>
#include <fstream>
#include <string>
#endif
#include "Word.h"
using namespace std;
const int WORD_SZ = 100;
Word** g_wordArray;
int g_arrSz;
static char filePath[ FILE_PATH_SZ ] = {};
void FreeWordArray();
int main( const int argc, const char **argv )
{
int wrdCount = 0;
char usrMenuOption = 0,
getFirstLetter = 0,
tmpArray[WORD_SZ] = {},
*getWord = 0;
string str,
str2;
ifstream inFile,
inFile2;
do
{
cout << "Please make a selection: \n\
a) Read a text file\n\
b) Remove words starting with letter\n\
c) Print words to console\n\
d) Quit\n";
cin >> usrMenuOption;
switch( usrMenuOption )
{
case'A':
case'a':
cout << "Enter a file name: ";
cin.sync();
cin >> filePath;
inFile.open( filePath );
if ( !inFile ) return -1;
inFile >> str; // prime the eof flag
while ( !inFile.eof() )
{
inFile >> str;
wrdCount++;
g_wordArray = new Word *[wrdCount];
}
inFile.close();
inFile2.open( filePath );
while( !inFile2.eof() )
{
inFile2 >> str2;
for ( unsigned x = 0; x < str2.length(); x++ )
g_wordArray[x] = new Word( str2.c_str() );
}
cout << wrdCount << " Words read from the file " << endl;
inFile2.close();
break;
case'B':
case'b':
getFirstLetter = g_wordArray[wrdCount]->GetFirstLetterLower();
//getWord = g_wordArray[wrdCount]->GetWord();
cout << getWord << endl;
break;
case'C':
case'c':
break;
case'D':
case'd':
cout << "Quit Requested. " << endl;
break;
default:
cout << '"' << usrMenuOption << '"' << " Not Defined! " << endl;
}
} while (usrMenuOption != 'D' && usrMenuOption != 'd');
#ifdef _DEBUG
_CrtDumpMemoryLeaks();
#endif
cin.ignore();
return 0;
}
void FreeWordArray()
{
// free the memory that is allocated
return;
}发布于 2009-04-18 03:56:52
编辑:我把这个编辑放在最上面,因为它直接回答了为什么Word被破坏的问题。您的复制构造函数错误:
Word::Word( const Word* theObject )
{
ptr_ = theObject->ptr_;
len_ = theObject->len_;
}这不会复制theObject->ptr_所指向的内容,只会复制指针。因此,您实际上有两个Word对象指向相同的内部字符串。当一个Word对象被删除时,这会变得非常糟糕。一个适当的实现(使用您所使用的技术,我建议使用它们)将如下所示:
Word::Word( const Word* theObject )
{
ptr_ = new char[theObject->len_ + 1 ];
strcpy( ptr_, theObject->ptr_ );
len_ = theObject->len_;
}编辑: Earwicker还注意到了以下内容:
...尽管该“复制构造函数”不是复制构造函数。因此,编译器生成的那个仍然存在,并执行相同的成员复制,因此同样的问题仍然存在。
为了解决这个问题,你需要创建一个合适的拷贝构造函数,它应该具有原型:
Word::Word(const Word &theObject);还有这里的代码:
while ( !inFile.eof() )
{
inFile >> str;
wrdCount++;
g_wordArray = new Word *[wrdCount];
}像筛子一样漏水!在读取每个单词之后,您重新分配g_wordArray,并且完全忘记删除前一个单词。我将再次使用您尝试使用的技术展示一个合理的实现。
while (inFile >> str)
{
inFile >> str;
wrdCount++;
}
g_wordArray = new Word *[wrdCount];注意它是如何计算单词的,然后在知道要分配多少之后,一次分配房间。现在,最多可以将g_wordArray用于wrdCount word对象。
原始答案:
为什么不直接用std::string替换Word类呢?这将使代码变得更小,更容易使用。
如果这对你来说更容易,只需这样做:
typedef std::string Word;然后你可以这样做:
Word word("hello");
char first_char = word[0];此外,它还有一个额外的好处,即不再需要使用.c_str()成员来获取c样式的字符串。
编辑:
我也会把你的g_wordArray改成std::vector<Word>。这样你就可以简单地做到这一点:
g_wordArray.push_back(Word(str));不再动态分配!这一切都是为你准备的。字数组的大小将仅受您拥有的内存量的限制,因为当您使用push_back()时,std::vector会根据需要增长。
此外,如果您执行this...guess操作来获取单词计数,则只需执行以下操作:
g_wordArray.size();不需要手动记录它们的数量!
编辑:
同样,这段代码也被破坏了:
while( !inFile2.eof() )
{
inFile2 >> str2;
...
}因为在您尝试读取之后,直到才会设置eof,所以最好使用以下模式:
while(inFile2 >> str2)
{
...
}它将在EOF上正确停止。
底线是,如果你做得对,你应该只需要写很少的实际代码。
编辑:
这里有一个我认为你想要的简单直接的实现。从菜单项看,用户的意图似乎是首先选择选项'a‘,然后选择'b’0次或多次以过滤掉一些单词,最后选择c打印结果(每行一个单词)。此外,选项'D‘并不是真正需要的,因为点击Ctrl+D会向程序发送一个EOF并使"while(std::cin >> option)“测试失败。从而结束该程序。(至少在我的操作系统中,它可能是windows版的Ctrl+Z` )。
此外,它也没有处理标点符号(您的也没有),但它是这样的:
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <functional>
#include <iterator>
struct starts_with : public std::binary_function<std::string, char, bool> {
bool operator()(const std::string &s, char ch) const {
return s[0] == ch;
}
};
void print_prompt() {
std::cout << "Please make a selection: \na) Read a text file\nb) Remove words starting with letter\nc) Print words to console" << std::endl;
}
int main( const int argc, const char **argv) {
std::vector<std::string> file_words;
char option;
print_prompt();
while(std::cin >> option) {
switch(option) {
case 'a':
case 'A':
std::cout << "Enter a file name: ";
// scope so we can have locals declared
{
std::string filename;
std::string word;
std::cin >> filename;
int word_count = 0;
std::ifstream file(filename.c_str());
while(file >> word) {
file_words.push_back(word);
}
std::cout << file_words.size() << " Words read from the file " << std::endl;
}
break;
case 'b':
case 'B':
// scope so we can have locals declared
{
std::cout << "Enter letter to filter: ";
char letter;
std::cin >> letter;
// remove all words starting with a certain char
file_words.erase(std::remove_if(file_words.begin(), file_words.end(), std::bind2nd(starts_with(), letter)), file_words.end());
}
break;
case 'c':
case 'C':
// output each word to std::cout separated by newlines
std::copy(file_words.begin(), file_words.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
break;
}
print_prompt();
}
return 0;
}发布于 2009-04-18 04:01:17
在不费力查看整个main.cpp的情况下,我确实注意到构造函数/析构函数集中有一个问题:
Word::Word( const Word* theObject )
{
ptr_ = theObject->ptr_;
len_ = theObject->len_;
}
Word::~Word()
{
delete [] ptr_;
ptr_ = NULL;
}请注意,在复制构造函数中,您只需分配内部指针来匹配要复制的对象。但是在你的析构函数中,你会删除内部指针上的数据。
这就是它可能会变得不舒服的地方:
Word w1 = Word("hello");
Word w2 = Word(w1);
delete w2;现在,你的第一个单词包含什么?该指针将存在,但它引用的数据已在w2的析构函数中删除。
他们称它为“复制构造函数”,因为这就是你应该做的:复制它。
发布于 2009-04-18 03:59:50
g_wordArray[wrdCount]是有效的Word对象吗?我的C++是生锈的,但在我看来,这超出了数组的末尾。此外,您似乎在inFile2循环中反复践踏g_wordArray的内容:对于您读入str2的每个字符串,都需要重新初始化g_wordArray中的第一个str2.length()条目。这就解释了成员变量的明显混乱。最后,我不确定这一点,但是在将新值读入str2之后,str2.c_str()返回的指针是否仍然有效?因此,您的GetWord()循环可能会从strlen获得一个垃圾值,然后进入never land。
https://stackoverflow.com/questions/762833
复制相似问题