When dealing with offset arrrays (using position 0 to indicate character 32), it is important for readability to use symmetrical access patterns for the process. In your case, you load the values as c-' '
, but what you use to read them, is accessed by i = 32; i < 127
.... and this asymmetrical access is inconvenient.
You also have no handling for out-of-bound characters.... can you trust your input sources to not have a carriage return, or a tab? Even esoteric null characters, or other binary values. I would have a catch-all 'bucket' for invalid values. That will prevent segfaults or other undefined actions.
You have a small bug in your code. In the print-loop, you increment the last character received.... what is this line for in the 'print' loops:
++histogram[c-' '];
Finally, for code reuse, it is often important to extract your functionality to a single reentrant method, other than the main method. Consider a signature like:
void histogram(const int offset, const int range)
where your histogram can be configured to take an offset position, and range, like:
histogram('a', 'z' - 'a' + 1);
which will count just the lower-case letters...
Something like:
#include <stdio.h>
#include <memory.h>
void histogram(const int offset, const int range) {
int histogram[range];
memset(histogram, 0, sizeof(histogram));
int special = 0;
int c;
while ((c = getchar()) != EOF) {
if (c < offset || c >= (offset + range)) {
special++;
} else {
++histogram[c - offset];
}
}
for (int i = 0; i < range; ++i) {
c = i + offset;
printf("%c ", c);
for (int j = 0; j < histogram[i]; ++j) {
putchar('x');
}
putchar('\n');
}
printf("- ");
for (int j = 0; j < special; j++) {
putchar('x');
}
putchar('\n');
}
int main(void) {
histogram(' ', 95);
}