iDouglas
iDouglas

Reputation: 13

Why wont this print any output? (c programming language)

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.

Upvotes: 1

Views: 160

Answers (1)

David C. Rankin
David C. Rankin

Reputation: 84521

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.

Upvotes: 1

Related Questions