0

I'm writing Huffman coding and everything was OK, until I tried to save the result into the archived file. Our teacher offered us to do it with such function (it takes each time a bit and after taking 8 of them should output a byte):

long buff=0;
int counter=0;
std::ofstream out("output", std::iostream::binary);

void putbit(bool b)
{
    buff<<=1;
    if (b) buff++;
    counter++;
    if (counter>=8)
    {
        out.put(buff);

        counter=0;
        buff=0;    
    }
}

I tried an example with inputting sequence of bits like this:

0011001011001101111010010001000001010101101100

but the output file in binary mode includes just: 1111111

As buff variable has the correct numbers (25 102 250 68 21 108) I suggested that I wrote the code in my notebook incorrectly and something is wrong with this line:

out.put(buff);

I tried to remove it with this line:

out << buff;

but got: 1111111111111111 Another way was:

out.write((char *) &buff, 8);

which gives:

100000001000000010000000100000001000000010000000

It look like the closest to the correct answer, but still doesn't work correctly.

Maybe I don't understand something about file output.

Question:

Could you explain me how to make it work and why previous variants are wrong?

UPD: The input comes from this function:

void code(std::vector<bool> cur, std::vector<bool> sh, std::vector<bool>* codes, Node* r)
{
    if (r->l)
    {
        cur.push_back(0);
        if (r->l->symb)
        {
            putbit(0);
            codes[(int)r->l->symb] = cur;

            for (int i=7; i>=0; i--)
            {
                if ((int)r->l->symb & (1 << i))
                putbit(1);
                else putbit(0);
            }
        }
        else
        {
        putbit(0);
        code(cur, sh, codes, r->l);
        }
        cur.pop_back();
    }
    if (r->r)
    {
        cur.push_back(1);
        if (r->r->symb)
        {
            putbit(1);
            codes[(int)r->r->symb] = cur;

            for (int i=7; i>=0; i--)
            {
                if ((int)r->r->symb & (1 << i))
                putbit(1);
                else putbit(0);
            }
        }
        else
        {
        putbit(1);
        code(cur, sh, codes, r->r);
        }
        cur.pop_back();
    }
}
7
  • The only thing I see wrong with that code is that you're not checking the return values of the functions for errors. Commented Sep 28, 2015 at 16:56
  • I just ran your code on your input, and it produced correct file. Can you show the code you use to call your function? Commented Sep 28, 2015 at 17:04
  • I actually ran your code and it works, although I would use a char rather than a long for the buffer variable. Perhaps show us how you're actually using this function in your code? Also, what are the "correct numbers (25 102 250 68 21 108)"? You should tell us what you're trying to achieve. Commented Sep 28, 2015 at 17:05
  • asig and Ishamael, could you tell which of the variants worked? asig, I meant that binary operations worked correctly and before outputting into file buff had the correc value Commented Sep 28, 2015 at 17:11
  • @Tami I straight copy pasted your function, with out.put( buff ). I understand what you meant now. Commented Sep 28, 2015 at 17:14

1 Answer 1

1

The thing is, your putbit function is working (though its terrible, you use globals and your buffer should be a char). For example, this is how I tested your function.

out.open( "outfile", std::ios::binary ); 
if ( out.is_open() ) {
    putbit(1);
    putbit(1);
    putbit(0);
    putbit(1);

    putbit(0);
    putbit(1);
    putbit(0);
    putbit(0);

    out.close();
}

This should ouput 1101 0100 or d4 in hex.

I believe this an XY problem. The problem you're trying to solve is not in the putbit function but rather on the way you use it and in your algorithm.

You said that you had the right values before putting your data to the output file. There are many similar questions to your in stackoverflow, just look for them.

The real problem is that the putbit function is not enough to solve your problems. You rely of the fact that it will write a byte after you call it 8 times. What if you write less than 8 bytes? Also, you never flush your file (at least in the code you posted) so there's no guarantee that all data will be written.

First you must understand how file handles (streams) work. Open your file locally, check if it's open and close it when you're done. Closing also guarantees that all data in the file buffer is written to the file.

outfile.open( "output", std::ios::binary );
if ( outfile.is_open() ) {
    // ... use file ...
    outfile.close();
}
else {
    // Couldnt open file!
}

Other questions solve this by writing, or using, a BitStream. It would look somewhat like this,

class OutBitstream {
public:
    OutBitstream();
    ~OutBitstream(); // close file

    bool isOpen();
    void open( const std::string &file );
    void close(); // close file, also write pending bits

    void writeBit( bool b ); // or putbit, use the names you prefer
    void writeByte( char c );

    void writePendingBits(); // write bits in the buffer they may
    // be less than 8 so you may have to do some padding

private:
    std::ofstream _out;
    char _bitBuffer; //or std::bitset<8>
    int _numbits;
};

With this interface it should be easier to handle bit input. No globals as well. I hope that helps.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.