Your compiler should be warning you that the index for your nletter array will be out of bounds -- which will invoke Undefined Behavior..
The problem causing you to write beyond the bounds of nletter is your failure to insure the indexing you use runs 0-25. Specifically you attempt:
++nletter[c];
where c will contain the ASCII value from 'a' - 'z' (or 97 - 122) see: ASCIItable.com. That is well above the usable indexes available (0 - 25) resulting from your declaration of: int nletter[26]; (recall, arrays are indexed from 0 to n-1 in C).
To prevent writing beyond the bounds of your array, you need to normalize the indexes such that 'a' will correspond to 0 and 'z' will correspond to 25. You do this by simply subtracting 'a' from the value of c, e.g.
++nletter[c - 'a'];
although I prefer the post-increment operator here, so:
nletter[c - 'a']++;
(the choice of the increment operator is yours -- the result is the same)
Putting it altogether, and adding a few clean-ups as described in the comments below, you could do something like:
#include <stdio.h>
int main (void) /* main() is a function that return type int */
{
int c, i, nwhite, nother;
int nletter[26] = {0}; /* {0} will initialize nletter */
nwhite = nother = 0;
while ((c = getchar()) != EOF) {
if ('a' <= c && c <= 'z')
nletter[c - 'a']++; /* you want indexes from 0-25 */
else if (c == ' ' || c == '\n' || c== '\t')
nwhite++;
else
nother++;
}
printf ("Letter: 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\n"
"Occurences:");
for (i = 0; i < 26; ++i)
printf ("%2d", nletter[i]); /* use the field-width modifier to */
/* insure output of 2 spaces per-int */
printf("\nwhite space = %d, other = %d\n", nwhite, nother);
return 0;
}
(Note: you can simplify further by including ctype.h and checking islower(c) instead of 'a' <= c && c <= 'z' and using isspace(c) instead of c == ' ' || c == '\n' || c== '\t', but since your Question didn't specify whether you could use anything but stdio.h I left the manual checks in place.)
Example Use/Output
$ echo "abcdefg hijklmnop qrstuv wxyzz" | ./bin/letterfreq
Letter: 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
Occurences: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
white space = 4, other = 0
(if testing on windows, omit the quotation marks or you will see other = 2)
If you are just getting started, then always compile with "warnings-enabled" and read and fix all warnings -- do not accept code until it compiles cleanly -- without a single warning. That will catch most problems before you end up scratching your head for hours. For gcc/clang, that means adding, at minimum, -Wall -Wextra to your compile string (you can add -pedantic for a few more, and adding -Wshadow is helpful). For VS, use /W3 -- the /Wall for VS contains quite a few non-code related suggestions as warnings.
A compile string for this code would look like:
gcc
gcc -Wall -Wextra -pedantic -Wshadow -std=c11 -Ofast -o letterfreq letterfreq.c
VS
cl /nologo /W3 /Ox /Feletterfreq /Tc letterfreq.c
In either case, the code should compile without warning.
CTRL+Dafter giving inputabcdefg hijklmnop qrstuv wxyzzas when you pressCtrl+dthen it detectsEOF.if ('a' <= c && c <= 'z') { /* do your stuff */ }rather than that long conflagration ofc == 'a' || c == 'b' || ...? Even better, includectype.hand just checkif (islower(c)) { /* do your stuff */ }