指针问题 2 [有效的 C++ 语法] [英] Pointer Issues 2 [Valid C++ Syntax]

查看:60
本文介绍了指针问题 2 [有效的 C++ 语法]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此版本正在运行.我在整个代码中都添加了 // 注释,以更好地说明我遇到的问题.该程序依赖于读取文本文件.以包含标点符号的段落格式.

This version is working. I've made // comments throughout my code to better illustrate what I am having trouble with. The program is dependent on reading a text file. In the format of paragraphs with punctuation included.

您可以将以上内容复制到文本文件中并运行该程序.

One could copy this and the above into a text file and run the program.

//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;
}

推荐答案

我已将此编辑放在顶部,因为它直接回答了您关于 Word 为何损坏的问题.您的复制构造函数是错误的:

I've put this edit at the top since it directly answers your question of why Word is broken. Your copy constructor is wrong:

Word::Word( const Word* theObject ) 
{
    ptr_ = theObject->ptr_;
    len_ = theObject->len_;
}

这不会复制theObject->ptr_ 指向的内容,只是复制指针.因此,您实际上有两个 Word 对象指向同一个内部字符串.当 Word 对象被删除时,这会变得非常糟糕.一个正确的实现(使用你所做的技术,我建议不要使用它们)应该是这样的:

this doesn't make a copy of what theObject->ptr_ points to, just the pointer. So you effectively have two Word objects pointing to the same internal string. This gets very bad when a Word object gets deleted. A proper implementation (using the techniques you did, I recomend against them) would be like this:

Word::Word( const Word* theObject ) 
{
    ptr_ = new char[theObject->len_ + 1 ];
    strcpy( ptr_, theObject->ptr_  );  
    len_ = theObject->len_;
}

Earwicker 还注意到以下内容:

Earwicker noted the following as well:

...虽然那个复制构造函数"不是复制构造函数.所以编译器生成的仍然会存在,并在成员上做同样的事情复制,因此同样的问题仍然存在.

... although that "copy constructor" is not a copy constructor. So the compiler-generated one will still exist, and does the same memberwise copy, and therefore the same problem still exists.

为了解决这个问题,你需要制作一个适当的复制构造函数,它应该有原型:

To remedy that, you'll need to make a proper copy constructor which should have the prototype:

Word::Word(const Word &theObject);

还有这里的代码:

while ( !inFile.eof() )
{        
    inFile >> str;
    wrdCount++;
    g_wordArray = new Word *[wrdCount];
}

像筛子一样漏水!您在读取每个单词后重新分配 g_wordArray 并且完全忘记删除前一个.我将再次展示使用您尝试使用的技术的合理实现.

leaks like sieve! You reallocate g_wordArray after every word is read and entirely forget to delete the previous one. Once again I'll show a sane implementation using the techniques you are attempting to use.

while (inFile >> str)
{        
    inFile >> str;
    wrdCount++;
}
g_wordArray = new Word *[wrdCount];

注意它如何计算字数,然后在知道要分配多少空间后一次分配空间.现在 g_wordArray 已准备好用于最多 wrdCount 个单词对象.

Notice how it counts the words, then allocates room once, after it knows how much to allocate. Now g_wordArray is ready to be used for up to wrdCount word objects.

原始答案:

为什么不直接用 std::string 替换 Word 类?这将使代码更小,更易于使用.

why don't you just replace the Word class with std::string? It would make the code much smaller and easier to work with.

如果它让你更轻松,就这样做:

If it makes it easier for you, just do this:

typedef std::string Word;

那么你可以这样做:

Word word("hello");
char first_char = word[0];

此外,它还具有额外的好处,您无需使用 .c_str() 成员来获取 c 样式字符串.

plus it has the added bonus of removing the need for you to use the .c_str() member to get the c-style string.

我也会将您的 g_wordArray 更改为一个 std::vector.这样你就可以简单地做到这一点:

I would also change your g_wordArray to just be a std::vector<Word>. That way you can simple do this:

g_wordArray.push_back(Word(str));

没有更多的动态分配!这一切都为你完成.字数组的大小仅受您拥有的 RAM 量的限制,因为当您使用 push_back() 时,std::vector 会根据需要增长.

no more dynamic allocation! it's all done for you. Size of the word array will be limited only by the amount of RAM you have, because std::vector grows as needed when you use push_back().

此外,如果您这样做...猜猜如何计算字数,您只需这样做:

Also, if you do this...guess what to get the word count you simply do this:

g_wordArray.size();

无需手动跟踪它们的数量!

no need to manually keep track of the number of them!

此外,此代码已损坏:

while( !inFile2.eof() )
{
    inFile2 >> str2;
    ...
}

因为 eof 直到您尝试读取 之后 才会设置,所以最好使用此模式:

because eof isn't set till after you attempt a read, you are better off using this pattern:

while(inFile2 >> str2)
{
    ...
}

这将在 EOF 上正确停止.

which will correctly stop on EOF.

最重要的是,如果你做对了,你需要编写的实际代码应该很少.

这是我认为您想要的直接实现示例.从菜单项看来,意图是让用户首先选择选项a",然后选择b"零次或多次以过滤掉一些单词,最后 c 打印结果(每行一个单词).此外,选项 'D' 并不是真正需要的,因为点击 Ctrl+D 会向程序发送一个 EOF 并使 "while(std::cin >> option)"测试失败.从而结束程序.(至少在我的操作系统中,对于 Windows,它可能是 Ctrl+Z`).

Here's a sample straight forward implementation of what I think you want. From the menu items it seems that the intention is for the user to choose option 'a' first, then 'b' zero or more times to filter out some words, then finally c to print the results (one word per line). Also, option 'D' isn't really needed since hitting Ctrl+D sends an EOF to the program and makes the "while(std::cin >> option)" test fail. Thus ending the program. (At least in my OS, it might be Ctrl+Z` for windows).

处理标点符号也毫不费力(你的也没有),但它是:

Also it makes no effort (neither did yours) to deal with punctuation, but here it is:

#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;
}

这篇关于指针问题 2 [有效的 C++ 语法]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆