/*
* Compute a histogram of the bytes in the input file. Each byte is
* printed numerically and as an ASCII character (if it is one).
*/
#include <iostream>
#include <iomanip>
#include <string>
#include <cmath>
using namespace std;
/*
* Print one line of the histogram. It receives the character to print,
* the number of times it apeared, the maximum count, and the number of
* digits to display in the character count values.
*/
void prhistline(int chcode, int count, int maxct, int cntdigits)
{
// Names for the low-valued control characters of the ASCII set.
string ascnames[] = {
"nul", "soh", "stx", "etx", "eot",
"enq", "ack", "bel", "bs ", "ht ",
"lf ", "vt ", "ff ", "cr ", "so ",
"si ", "dle", "dc1", "dc2", "dc3",
"dc4", "nak", "syn", "etb", "can",
"em ", "sub", "esc", "fs ", "gs ",
"rs " };
// If the count is zero, omit the line.
if(count == 0) return;
// Print the character code, base 16 filled with zeros to width 2.
cout << "x" << setw(2) << setfill('0') << hex << chcode << " "
<< setfill(' ') << dec;
/*
* Print the character using an appropriate form.
*/
// Check the range to see the type of character.
if(chcode < sizeof ascnames / sizeof ascnames[0])
// Low ASCII control codes.
cout << ascnames[chcode];
else if(chcode == 127)
// The only high ASCII control code.
cout << "del";
else if(chcode > 127)
// Byte above the ASCII set. Input must be a binary file,
// or uses some non-ASCII encoding. Just put spaces.
cout << " ";
else
// An actual character.
cout << (char)chcode << " ";
// Print the count.
cout << " " << setw(cntdigits) << count << " ";
// Print the bar. This takes the ratio of the actual count to the
// maximum count, then computes that portion of the available space
// as the bar length. */
int barsize =
(int)((79 - 9 - cntdigits) * ((double)count / (double)maxct) + 0.5);
while(barsize--) cout << "#";
cout << endl;
}
/*
* Read the file and print the histogram.
*/
const int HISSIZE = 256;
int main()
{
int hist[HISSIZE]; // Count of bytes.
int maxct = 0; // Maximum of any count.
int cntdigits; // Num digits for printing count.
// Zero out all the counts.
for(int & c: hist) { c = 0; }
// Read the input file and count each character.
char inch;
while(cin.get(inch)) {
// Update the count, and the maximum.
if(++hist[inch] > maxct)
maxct = hist[inch];
}
// Compute the number of spaces needed for printing the counts
cntdigits = (int)(log10((float)maxct) + 1.00001);
// Print the histogram.
for(int m = 0; m < HISSIZE; ++m)
prhistline(m, hist[m], maxct, cntdigits);
}
This program is just a mainly a chance to use arrays. Some
new things here:
- Certain #include headers which start with the letter c
represent C++ versions of plain C headers. For instance, in plain C,
cmath is named math.h. Either name works in C++,
but using cmath more C++ish.
- cmath contains the base 10 logarithm function log10
used in the main.
- Notice the array ascnames is initialized with a list of values
enclosed in curly braces. This is similar to Java.
- The for loop near the top of main uses the
& for the same reason function parameters do. Otherwise
our assignment of c wouldn't change anything.