0

This is my code. My point is to take string input and count how many of each letter occurs

#include <stdio.h>
#include <ctype.h>


int main()
{
    int c1;
    int a=0, b=0, c=0, d=0, e=0, f=0, g=0, h=0, i=0, j=0, k=0, l=0, m=0, n=0, o=0, p=0, q=0, r=0, s=0, t=0, u=0, v=0, w=0, x=0 , y=0, z=0;

    while (( c1=getchar()) != EOF)
        if (isalpha(tolower(c1)) != 0) {

            if (tolower(c1) == 97) {  // Character = 'a'
                a += 1;
            }

            else if (tolower(c1) == 98) { // Character = 'b'
                b += 1;
            }

            else if (tolower(c1) == 99) { // Character = 'c'
                c += 1;
            }

            .
            .
            .

        }
    return 0;
}

Next I want to printf result in vertical. Could you give me some hints. For example,

input: ABC---Ddhhh

output:

       *
   *   *
****   *
abcdefghijklmnopqrstuvwxyz
  • just printf each char separately , or use newline? https://stackoverflow.com/questions/10693431/how-do-i-add-a-newline-using-printf – user3682728 Oct 21 '22 at 04:31
  • Can you please show your code for how you're printing? Or do you not have that yet? – Millar248 Oct 21 '22 at 04:32
  • Avoid using *MagicNumbers* use `'a'` when you mean '`a'` not `97`, `'b'` when you mean `'b'`, not `98` and so on. See [ASCII Table](https://www.asciitable.com/) – David C. Rankin Oct 21 '22 at 04:39

3 Answers3

1

Any time you have more than one or two variables that do the same thing, it is time to use a data structure; in this case, an array. You will want something like

int counts[26];

instead of twenty six different variables, and only have one statement instead of 26 different if clauses. Then you can say

counts[lower(c1) - 97]

instead of a, b... z (after checking that lower(c1) is one of the letters).

The way to print the output is based on these insights:

  • The number of lines above the alphabet is the highest number in counts (let's call it maxcount). It would be 3 in your example.
  • For each line, there is a * if that letter's count is at least maxcount - line (i.e. in 0th line, there is a * if there is at least 3 - 0 counts of that character), otherwise there's a space.
Amadan
  • 191,408
  • 23
  • 240
  • 301
1

While it may be a struggle learning, it's important to spend time learning and not simply copy/pasting lines of code to have a big program. The best code is the briefest code that achieves the objective.

As others have said, the contiguous alphabet should cause you to use a contiguous array of counters, not individual variables. (One typo and your results will be wrong.) Nesting isalpha(tolower(c)) is not needed. And, you've shown how you might count, but not shown code that would output the desired results.

This is for you to study, learn and grow as a coder.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// Try to write functions; blocks of code that do what you want in compartments
void countAndGraph( char *str ) {
    int max = 0, cnt[26] = { 0 }; // initialises 'max' and 26 counters

    for( char *p = str; *p; p++ ) // as long as there is a character
        if( isalpha( *p ) ) {     // if it is alphabetic
            int i = tolower( *p ) - 'a'; // convert ASCII character to value 0-25
            if( ++cnt[ i ] > max ) // increment the right counter and test against max
                max = cnt[ i ]; // 'max' - the ceiling - keeps getting higher
        }

    for( ; max; max-- ) { // lower the ceiling
        for( int i = 0; i < 26; i++ ) // for 26 alphabetic characters
            putchar( " *"[cnt[i]>=max] ); // output ' ' or '*' if count at/above ceiling
        putchar( '\n' ); // newline
    }
    puts( "abcdefghijklmnopqrstuvwxyz" ); // reference alphabet string
    puts( str ); // the string that's been analysed
    puts( "" );
}

int main() {
    char *tst[] = { // three test strings to demonstrate
        "The quick brown fox jumps over the lazy dogs",
        "Sally sells seashells by the sea shore",
        "I wish I was what I was when I wished I was what I am now",
    };
    const size_t nTst = sizeof tst/sizeof tst[0];

    for( size_t i = 0; i < nTst; i++ ) // count and graph each of the strings
        countAndGraph( tst[i] );

    return 0;
}
              *
    *         *
    *  *      *  ****
**************************
abcdefghijklmnopqrstuvwxyz
The quick brown fox jumps over the lazy dogs

                  *
                  *
    *      *      *
    *      *      *
    *      *      *
*   *  *   *      *
*   *  *   *      *     *
**  *  *   *  *  ***    *
abcdefghijklmnopqrstuvwxyz
Sally sells seashells by the sea shore

                      *
        *             *
        *             *
*       *             *
*      **         *   *
*      **         *   *
*      **         *   *
*   *  **    *    **  *
*  **  **   ***   **  *
abcdefghijklmnopqrstuvwxyz
I wish I was what I was when I wished I was what I am now

Now that you have this code, an exercise would be to print the bar graph in ascending/descending order. Don't stop with this one version; push it to a new educational experience.

                         *
                         *
                         *
                         *
                        **
                       ***
                      ****
                 *********
             *************
            **************
          ****************
         *****************
        ******************
fzcxqpjkuvywnbmdgrloshiate
'Twas brillig, and the slithy toves
Did gyre and gimble in the wabe:
All mimsy were the borogoves,
And the mome raths outgrabe.
Fe2O3
  • 6,077
  • 2
  • 4
  • 20
-1

I think you can just print one at a time.

#include <stdio.h>
#include <ctype.h>


int main()
{
    int c1;
    int a=0, b=0, c=0, d=0, e=0, f=0, g=0, h=0, i=0, j=0, k=0, l=0, m=0, n=0, o=0, p=0, q=0, r=0, s=0, t=0, u=0, v=0, w=0, x=0 , y=0, z=0;
    // I might do an array here, so you can loop through later.
    int letters[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};


    while (( c1=getchar()) != EOF) {
        if (isalpha(tolower(c1)) != 0) {

            if (tolower(c1) == 97) {  // Character = 'a'
                a += 1;
                letters[0]++;
            }

            else if (tolower(c1) == 98) { // Character = 'b'
                b += 1;
                letters[1]++;
            }

            else if (tolower(c1) == 99) { // Character = 'c'
                c += 1;
                letters[2]++;
            }

            .
            .
            .

        }
    }
    int ii;
    for (ii = 0; ii < 26; ii++) {
        printf("%d\n", letters[ii]);
    }
    return 0;
}
Millar248
  • 403
  • 8
  • 18
  • Why not `char lc = tolower(ci);` and `letters[lc - 'a']++;` and forget the `if .. else if ... ... else`? You can initialize `int letters[26] = {0};` and avoid a lot of typing `:)` – David C. Rankin Oct 21 '22 at 04:42
  • Ah true, I forgot about initializing. Haven't done C in a while. I left the if else's because the original question had that, and felt like remaining close to what they had in their question would provide more insight to them specifically. I agree though, the else if's are cumbersome. – Millar248 Oct 21 '22 at 04:57
  • @DavidC.Rankin Could you please decribe this code 'letters[lc - 'a']++;' for me, like how it works? I search on the internet but still don't understand. What is "-" sign in the middle using for? –  Oct 21 '22 at 04:59
  • How does this produce the requires output (the ASCII art histogram chart with vertical bars)? – hyde Oct 21 '22 at 05:06
  • When you create `char lc = tolower (ci);` you store the lowercase representation in `lc`. Using the [ASCII Table](https://www.asciitable.com/), you can see the lowercase `'a'` has the ASCII value `97`. So when you use `lc - 'a'` as the index you automatically map the correct character to the correct index. Take `'b'` for example, looking at the ASCII Table, you can see `'b' - 'a'` would give you the index `1` (correct), `'a' - 'a'` index `0` ... `'z' - 'a'` index `25`. A great way to simplify things. – David C. Rankin Oct 21 '22 at 05:11
  • For a full explanation of what is frequency array is, and how to use it, a fuller explanation is provided in answer to [How to remove duplicate char in string in C](https://stackoverflow.com/a/63255183/3422102). An example related to characters is [Find most frequent letter in C](https://stackoverflow.com/a/65462132/3422102). There many many ways you can apply this same logic. Which is what @Amadan did in his answer, just using `tolower(ci) - 'a'` as the index. See my *MagicNumber* comment under the original question. – David C. Rankin Oct 21 '22 at 05:16