I'm facing a slight problem with one of my projects. I am supposed to write a c program to calculate each character present in the input/file. (It's supposed to be a basic program.) The constraints - I cannot use the math.h library to produce log functions and obtain an output in the format:
1
5 1 2 0 2 2 5 8 4 3 6 6 2 5 5 7 2 1 1 2
7 9 8 1 7 2 4 1 0 0 4 5 0 2 2 5 2 6 3 6 6 3 7 0 2 2
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
The program is supposed to count the number of occurrences of each alphabetic letter (case insensitive) in the stdin input stream and display a histogram.
As you can see, the output is formatted vertically with each line printing the base 10 number of the position of the character. Now, this might seem silly, but what I have so far is this:
#include <stdio.h>
#include <ctype.h>
/*
int logBase10 (int num) {
method to calculate the log base 10 of num
}
*/
int main (int argc, char * argv[]) {
char alpha;
int count = 0;
int ascii[128] = {0};
while ( (alpha = getchar()) != EOF) {
count++;
ascii[(int)alpha]++;
alpha = getchar();
}
printf("Char \t Count \n");
printf("------------------------\n");
for (int i = 0; i < 127; i++) {
if(ascii[i] > 0) {
printf("%c \t %d \n", i, ascii[i]);
}
}
}
Which produces an output like this:
Char Count
------------------------
5
93
, 6
- 2
. 3
; 2
C 2
I 6
N 1
T 1
W 2
a 26
b 5
c 8
d 13
e 55
f 11
g 7
h 28
i 32
k 3
l 26
m 17
n 31
o 27
p 12
q 1
r 26
s 22
t 42
u 11
v 8
w 8
y 13
z 1
First off, my program is printing unwanted ascii characters (, ; - etc) and I am working on changing the print function to be more vertical, but I cannot figure out the log method at all. I know log(10) is 1 because 10^1 is 1, but I am having trouble figuring out how to use this to create the method itself. Also, for the extra characters, I tried using:
if(ascii[i] > 65 || ascii[i] < 90 || ascii[i] >= 97 || ascii[i] <= 122 ) {
printf("%c \t %d \n", i, ascii[i]);
}
to no avail. Trying that produced more gibberish characters instead.
Any help/feedback is appreciated.
The commenters have already pointed out issues with your code. Here's a version that counts only letters and prints vertical labels. It doesn't need <ctype.h>
or <math.h>
.
Each character hets a letter index which is a number from 0 to 25 for upper and lower case letters and −1 if the character isn't a letter. That reduces the array size to 26.
You could find out each digit with elaborate calculations, but the easiest way is to print the number to a string. snprintf
does this for you. You can right-align the number with a field width. The maximum value for a typical int
is about 2 billion, which has 10 digits. You should account for that, even if you had to pass in the whole Moby-Dick plus the Bible to get that many counts.
You can test whether you should start printing by assuming a width of ten digits first and checking whether the maximum count has ten digits, that is whether it is 1,000,000,000 or higher. Then divide that limit by 10 in each iteration.
Here's the code:
#include <stdio.h>
// return letter index or -1 for non-letter
int letter(int c)
{
if ('a' <= c && c <= 'z') return c - 'a';
if ('A' <= c && c <= 'Z') return c - 'A';
return -1;
}
int main(int argc, char * argv[])
{
int count[26] = {0}; // letter counts
char label[26][12]; // buffer for printing numbers
int limit = 1000000000; // smallest 10-digit number
int max = 0;
int i, j;
// read and count letters
while (1) {
int c = getchar();
if (c == EOF) break;
c = letter(c);
if (c >= 0) count[c]++;
}
// write auxiliary labels
for (i = 0; i < 26; i++) {
snprintf(label[i], sizeof(label[i]), "%10d", count[i]);
if (count[i] > max) max = count[i];
}
// print vertical labels
for (j = 0; j < 10; j++) {
if (max >= limit) {
for (i = 0; i < 26; i++) {
putchar(' ');
putchar(label[i][j]);
}
putchar('\n');
}
limit /= 10;
}
// print horizontal rule
for (i = 0; i < 26; i++) {
putchar('-');
putchar('-');
}
putchar('-');
putchar('\n');
// print letters
for (i = 0; i < 26; i++) {
putchar(' ');
putchar('A' + i);
}
putchar('\n');
return 0;
}
On your example, it produces:
1
5 1 2 0 2 2 5 8 4 3 6 6 2 5 5 7 2 1 1 2
7 9 8 1 7 2 4 1 0 0 4 5 0 2 2 5 2 6 3 6 6 3 7 0 2 2
-----------------------------------------------------
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z