Seekg(ios :: beg)没有返回到重定向输入的开头

时间:2013-07-27 20:28:54

标签: c++ input cin huffman-code seekg

我正在制作一个霍夫曼编码器并且这样做我需要读取输入(它总是一个重定向的文件)来记录频率,然后创建码本然后再次读取输入以便我可以编码它

我的问题是我目前正在尝试测试如何从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()实际上并没有重置输入。

2 个答案:

答案 0 :(得分: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。这可能是一个 强制定义std::streamposstd::ios_base::seekdir 一种方式,以便有一个隐含的转换 std::ios_base::seekdirstd::streampos,但在我看来,它 不应该,因为结果几乎肯定不是你想要的。 寻找文件的开头:

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

第三个问题:输入流中的错误是粘滞的。一旦你 到达文件末尾,该错误将保留,所有其他错误 在您清除错误之前,操作将是no-ops: std::cin.clear();

最后一条评论:你使用std::cin的事实让我担心。 它可能会起作用(虽然不能保证你可以寻求 在std::cin上,即使输入是从文件重定向的),但确实如此 意识到有没有方式可以输出霍夫曼的结果 编码为std::cout。它可以在Unix下运行,但可能没有 其他。霍夫曼编码要求文件以二进制模式打开, 对于std::cinstd::cout,情况绝非如此。

答案 1 :(得分: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);
}