2

我正在制作一个霍夫曼编码器,为此我需要读取输入(始终是重定向文件)以记录频率,然后创建代码本,然后再次读取输入,以便我可以对其进行编码。

我的问题是我目前正在尝试测试如何使文件从 cin 读取两次。

我在网上读到 cin.seekg(0) 或 cin.seekg(ios::beg) 或 cin.seekg(0, ios::beg) 只要文件被重定向而不是管道,都应该工作得很好。但是当我这样做时,它似乎对cin的位置没有任何作用。

这是我目前正在使用的代码:

#include<iostream>
#include"huffmanNode.h"

using namespace std;

    int main(){

    //create array that stores each character and it's frequency
    unsigned int frequencies[255];
    //initialize to zero
    for(int i=0; i<255; i++){
        frequencies[i] = 0;
    }

    //get input and increment the frequency of corresponding character
    char c;
    while(!cin.eof()){
        cin.get(c);
        frequencies[c]++;
    }

    //create initial leafe nodes for all characters that have appeared at least once
    for(int i=0; i<255; i++){

        if(frequencies[i] != 0){
            huffmanNode* tempNode = new huffmanNode(i, frequencies[i]);
        }
    }


    // test readout of the frequency list
    for(int i=0; i<255; i++){
        cout << "Character: " << (char)i << " Frequency: " << frequencies[i] << endl;;
    }

    //go back to beginning of input
    cin.seekg(ios::beg);

    //read over input again, incrementing frequencies. Should result in double the amount of frequencies
 **THIS IS WHERE IT LOOPS FOREVER**
    while(!cin.eof()){
        cin.get(c);
        frequencies[c]++;
    }

    //another test readout of the frequency list
    for(int i=0; i<255; i++){
        cout << "Character: " << (char)i << " Double Frequency: " << frequencies[i] << endl;
    }


    return 0;
}

调试显示它卡在第 40 行的 while 循环中,并且似乎不断获得换行符。为什么它不退出这个循环?我假设 cin.seekg() 实际上并没有重置输入。

4

2 回答 2

1

您的代码有几个问题。第一种是您使用输入 ( cin.get( c )) 的结果而不检查输入是否成功。这总是一个错误;在您的情况下,它可能只会导致计算(并稍后输出)最后一个字符两次,但它可能导致未定义的行为。在使用值输入之前,您必须在每次输入之后检查输入流是否处于良好状态。通常的做法是:

while ( cin.get( c ) ) // ...

,将输入直接放在循环条件中。

第二个是声明:

cin.seekg( std::ios::beg );

我实际上有点惊讶,这甚至编译:有两个重载seekg

std::istream::seekg( std::streampos );

std::istream::seekg( std::streamoff, std::ios_base::seekdir );

std::ios::beg有类型std::ios_base::seekdir。impementation 可以定义std::streamposandstd::ios_base::seekdir以某种方式从 std::ios_base::seekdirto进行隐式转换std::streampos,但在我看来,它不应该,因为结果几乎肯定不会是你想要的。寻找文件的开头:

std::cin.seekg( 0, std::ios_base::beg );

第三个问题:输入流中的错误是粘性的。到达文件末尾后,该错误将仍然存在,并且所有其他操作都将是无操作的,直到您清除错误为止: std::cin.clear();.

最后一条评论:你正在使用的事实让std::cin我担心。std::cin它可能会起作用(尽管无法保证您可以在std::cout. 它可以在 Unix 下工作,但在其他地方可能不行。霍夫曼编码要求文件以二进制模式打开,std::cinstd::cout.

于 2013-07-27T20:52:46.157 回答
0

这是我的 0.02 美元,使它更像 C++ 并解决您的查找问题:

#include <sstream>
#include <iostream>
#include <iomanip>
//#include"huffmanNode.h"

std::string slurp()
{
    std::stringstream ss;
    ss << std::cin.rdbuf();
    return ss.str();
}

void dump_freq(unsigned int (&frequencies)[255])
{
    int i = 0;
    for(auto freq : frequencies) {
        if (freq) {
            std::cout << "Character: " << 
                std::ios::hex << std::setw(2) << "0x" << i++ << 
                " Frequency: " << freq << std::endl;
        }
    }
}

int main() {

    const auto data = slurp();

    //create array that stores each character and it's frequency
    unsigned int frequencies[255] = { 0 };

    //get input and increment the frequency of corresponding character
    for(auto ch : data) frequencies[ch]++;

    //create initial leafe nodes for all characters that have appeared at least once
    for(int i=0; i<255; i++) {
        if(frequencies[i] != 0) {
            //huffmanNode* tempNode = new huffmanNode(i, frequencies[i]);
        }
    }

    // test readout of the frequency list
    dump_freq(frequencies);

    // read over input again, incrementing frequencies. Should result in double
    // the amount of frequencies
    for(auto ch : data) frequencies[ch]++;

    //another test readout of the frequency list
    dump_freq(frequencies);
}
于 2013-07-27T20:53:13.250 回答