1

Not sure why nothing is coming out, compiler finds no errors, it just runs and terminates a few seconds later, no output.

I'll give the source code and the input file's text.

Source code: letterArray.c

#include <stdio.h>

/* displays a histogram of the frequencies 
of letters in input */
main()
{
    int c, i, nwhite, nother;
    int nletter[26];

    nwhite = nother = 0;
    for (i = 0; i < 26; ++i)
        nletter[i] = 0;

    while ((c = getchar()) != EOF)
        if (c == 'a' || c == 'b' || c == 
'c' || c == 'd' || c == 'e' || c == 'f' || 
c == 'g' || c == 'h' || c == 'i' || c == 
'j' || c == 'k' || c == 'l' || c == 'm' || 
c == 'n' || c == 'o' || c == 'p' || c == 
'q' || c == 'r' || c == 's' || c == 't' || 
c == 'u' || c == 'v' || c == 'w' || c == 
'x' || c == 'y' || c == 'z')
            ++nletter[c];
        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 
\nOccurences:");        
        for (i = 0; i < 26; ++i)
            printf(" %d", nletter[i]);
        printf("\nwhite space = %d, other = 
%d\n", nwhite, nother);
}

Text input: input.txt

    abcdefg hijklmnop qrstuv wxyzz

I'm pretty new to c, and to programming in general. Any help would be appreciated.

9
  • you need to press CTRL+D after giving input abcdefg hijklmnop qrstuv wxyzz as when you press Ctrl+dthen it detects EOF. Commented Sep 2, 2018 at 6:01
  • Recommended reading: How to debug small programs Commented Sep 2, 2018 at 6:07
  • The while loop terminates when it reaches the end of the input file. Commented Sep 2, 2018 at 6:07
  • I'm not sure what you mean. I'm running the executable in command prompt like this: letterArray.exe < input.txt Command prompt doesn't do anything with ctrl+d Commented Sep 2, 2018 at 6:21
  • 1
    Ever thought of if ('a' <= c && c <= 'z') { /* do your stuff */ } rather than that long conflagration of c == 'a' || c == 'b' || ...? Even better, include ctype.h and just check if (islower(c)) { /* do your stuff */ } Commented Sep 2, 2018 at 7:19

1 Answer 1

1

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.

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.