2

私はハフマン エンコーダーを作成しています。そのためには、入力 (常にリダイレクトされたファイル) を読み込んで周波数を記録し、コードブックを作成してから、入力を再度読み込んでエンコードできるようにする必要があります。

私の問題は、ファイルをcinから2回読み取る方法を現在テストしようとしていることです。

ファイルがリダイレクトされ、パイプされない限り、 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 )1 つ目は、入力が成功したことを確認せずに、入力 ( ) の結果を使用することです。これは常にエラーです。あなたの場合、おそらく最後の文字を 2 回カウント (および後で出力) するだけですが、未定義の動作が発生する可能性があります。各入力の後、値入力を使用する前に、入力ストリームが良好な状態であることを確認する必要があります。これを行う通常の方法は次のとおりです。

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

、入力を直接ループ状態にします。

2 つ目は次のステートメントです。

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

私は実際にこれがコンパイルされたことに少し驚いています: の2つのオーバーロードがありseekgます:

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

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

std::ios::begタイプがありstd::ios_base::seekdirます。からへの暗黙的な変換が行われるよう に、実装によってstd::streamposandを定義することは可能ですが、私の意見では、そうすべきではありません。ファイルの先頭にシークするには:std::ios_base::seekdirstd::ios_base::seekdirstd::streampos

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

3 番目の問題: 入力ストリームのエラーはスティッキーです。ファイルの終わりに到達すると、そのエラーは残り、エラーをクリアするまで、他のすべての操作はノーオペレーションになります: 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 に答える