MethequalsMath
MethequalsMath

Reputation: 49

K&R Exercise 1-14

So what I'm trying to do is to make a histogram of the frequency of a, b, c, d, and others. I was wondering why when I give the program an input of say abcde, other is counted more than one time when e only occurs once.

The output I'm looking for with input abcde is

 a:x
 b:x
 c:x
 d:x
 other:x

The actual K&R exercise is to print a histogram of the different characters that appear in an input. My code appears to be extremely inefficient, so I want to know if am I in the right direction to answering the exercise. Any guidance would be appreciated. The code is below.

#include <stdio.h>

main()
{
    int i, c, na, nb, nc, nd, nother;

    na = nb = nc = nd = nother = 0;

    while( (c = getchar()) != EOF ) {
        if(c == 'a')
            na++;
        if(c == 'b')
            nb++;
        if(c == 'c')
            nc++;
        if(c == 'd')
            nd++;
        else nother++;
    }

    printf("a:");
    for(i == 0; i < na; i++) {
        putchar('x');
    }

    printf("\nb:");
    for(i = 0; i < nb; i++) {
        putchar('x');
    }

    printf("\nc:");
    for(i = 0; i < nc; i++) {
        putchar('x');
    }

    printf("\nd:");
    for(i = 0;i < nc; i++) {
        putchar('x');
    }

    printf("\nother:");
    for(i = 0;i < nother; i++){
        putchar('x');
    }
}

Upvotes: 3

Views: 2729

Answers (5)

Student
Student

Reputation: 821

The Answer Book encourages the use of character classification functions provided by the standard library in order to identify printable characters from control characters and whitespaces.
Using them not only put the different types of characters into well-defined groups but also in case of this particular exercise can be used for the detailed representation of the final report.
For example, in the reading loop, isprint function makes it possible to count the total number of printable characters as

int printable = 0;
while ( (c = getchar()) != EOF )
    if ( isprint(c) )
        ++printable;

and at the same time discourages the programmer from formulating something like

if (c >= ' ' && c <= '~')

In fact, the possibilities are limitless. The following is a modified version of The Answer Book's solution.

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

#define MAXHIST 15  /* max length of histogram  */
#define MAXCHAR 128 /* max different characters */

int main()
{
    int c,
        i,
        len,         /* length of each bar      */
        maxvalue,    /* maximum value of cc[]   */
        cc[MAXCHAR], /* char frequency counters */
        totalc,      /* total chars of input    */
        whitec,      /* whitespaces chars       */
        digitc,      /* numeric chars           */
        upperc,      /* uppercase chars         */
        lowerc,      /* lowercase chars         */
        punctc;      /* punctuation marks       */

    totalc = whitec = digitc =
    upperc = lowerc = punctc = 0;

    for (int i = 0; i < MAXCHAR; ++i)
        cc[i] = 0;

    while ((c = getchar()) != EOF)
        if(c >= 0 && c < MAXCHAR) {
            ++cc[c];
            ++totalc;

            if      (isspace(c)) ++whitec;
            else if (isdigit(c)) ++digitc;
            else if (isalpha(c)) {
                if (isupper(c)) ++upperc;
                else            ++lowerc;
            }
            else if (ispunct(c)) ++punctc;
        }

    maxvalue = 0;
    for (i = 0; i < MAXCHAR; ++i)
        if (cc[i] > maxvalue)
            maxvalue = cc[i];

    printf("\n%s - %s - %s\n", "ASCII", "CH", "Freq");
    printf("~~~~~~~~~~~~~~~~~~~~\n");   
    for (i = 0; i < MAXCHAR; ++i) {
        if (cc[i] == 0)
            continue;
        if (isprint(i))
            printf("%5d - %2c - %5d : ", i, i, cc[i]);
        else
            printf("%5d -    - %5d : ", i, cc[i]);

        if (cc[i] > 0) {
            if ((len = cc[i] * MAXHIST / maxvalue) <= 0)
                len = 1;
        } else
            len = 0;

        while (len > 0) {
            putchar('*');
            --len;
        }
        putchar('\n');
    }

    printf("\n*** Detailed report ***\n");
    printf("Total # of chars      : %4d\n"
           "Total # of whitespaces: %4d\n"
           "Total # of numbers    : %4d\n"
           "Total # of letters    : %4d (%4d upper + %4d lower)\n"
           "Total # of puncts     : %4d",
           totalc, whitec, digitc, 
           upperc + lowerc, upperc, lowerc,
           punctc);
}

Sample Input (The OP's first paragraph)

so what I'm trying to do is to make a histogram of the frequency of a,b,c,d and others. I was wondering why when I give the program an input of say "abcde", 'other' is counted more than one time when 'e' only occurs once.

Sample Output

ASCII - CH - Freq
~~~~~~~~~~~~~~~~~~~~
   32 -    -    43 : ***************
   34 -  " -     2 : *
   39 -  ' -     5 : *
   44 -  , -     4 : *
   46 -  . -     2 : *
   73 -  I -     3 : *
   97 -  a -    12 : ****
   98 -  b -     2 : *
   99 -  c -     7 : **
  100 -  d -     6 : **
  101 -  e -    18 : ******
  102 -  f -     4 : *
  103 -  g -     5 : *
  104 -  h -    10 : ***
  105 -  i -     8 : **
  107 -  k -     1 : *
  108 -  l -     1 : *
  109 -  m -     6 : **
  110 -  n -    14 : ****
  111 -  o -    18 : ******
  112 -  p -     2 : *
  113 -  q -     1 : *
  114 -  r -    10 : ***
  115 -  s -     8 : **
  116 -  t -    13 : ****
  117 -  u -     4 : *
  118 -  v -     1 : *
  119 -  w -     6 : **
  121 -  y -     5 : *

*** Detailed report ***
Total # of chars      :  221
Total # of whitespaces:   43
Total # of numbers    :    0
Total # of letters    :  165 (   3 upper +  162 lower)
Total # of puncts     :   13 

Upvotes: 0

builder-7000
builder-7000

Reputation: 7647

#include <stdio.h>
main() {
  int c, i, n, nc;                                                            
  nc = '~' - ' '; // range of ascii values to count                           
  int ndigit[nc];                                                             
  for (i = 0; i < nc; ++i)                                                    
      ndigit[i] = 0;                                                          
  while ((c = getchar()) != EOF) {                                            
      ++ndigit[c-' '];                                                        
      if (c == '\n') {                                                        
          for (i = 0; i < nc; i++)                                            
              if (ndigit[i] != 0) {                                           
                  printf("%c: ", i + ' ');                                    
                  for (n = 0; n < ndigit[i]; n++) {                           
                      printf("-");                                            
                  }                                                           
                  printf("\n");                                               
              }                                                               
          for (i = 0; i < nc; ++i)                                            
              ndigit[i] = 0;                                                  
      }                                                                       
  }
}                                                                           

Sample input:

aa bbb cccc x

Output:

 : ---
a: --
b: ---
c: ----
x: -

Upvotes: 0

ksha
ksha

Reputation: 2087

#include<stdio.h>
main()
{
  int charcount[95],c,i=0,max=0;
  for(i=0;i<95;++i) /*Setting every array point to zero*/
    {
      charcount[i]=0;
    }
  while((c=getchar())!=EOF) /*Frequency of each character*/
    {    
      ++charcount[c-32];
    }
  for(i=0;i<95;++i) /*For character count of the longest word*/
    {
      if(max<charcount[i])
    max=charcount[i];
    }
  printf("\n");
  for(i=max;i>=0;--i) /*Printing the Vertical Histogram*/
    {
      for(c=0;c<95;++c)
    {
      if(charcount[c]!=0)
        {
          if((charcount[c]-i)<0)
        {
          printf("  ");
        }
          else if(i==0)printf("==");
          else printf(" X");
        }
    }
      printf("\n");
    }
  for(i=0;i<95;++i) /*Printing the Characters below the Histogram for reference*/
    {
      if(charcount[i]!=0)
    {
      if(i==0)printf("sp "); /*We would write "sp" that stands for space*/
      else printf("%c ",i+32);
    }
    }
  printf("\n");
}

VERTICAL ALIGNMENT

The OUTPUT looks like this: "This is not Sparta", yelled the soldier. The messenger walked away. :)

 X                                                
 X                                                
 X                   X                            
 X                   X                            
 X                   X                            
 X                   X                            
 X               X   X                     X      
 X               X   X         X           X      
 X               X X X   X X   X         X X X    
 X X     X     X X X X   X X   X   X X   X X X X X
 X X X X X X X X X X X X X X X X X X X X X X X X X
==================================================
sp " ) , . : S T a d e g h i k l m n o p r s t w y 

Upvotes: 0

aamermoquim
aamermoquim

Reputation: 13

First a little code to find out the characters for your system:

#include<stdio.h>

int main()
{
  int i;
  for(i=0; i < 128; ++i){
    printf("%3d ", i);
    putchar(i);
    printf("\n");
  }
  }

This will give you the 32 to 127 range. Then this works

#include <stdio.h>

/*Write a program to print a histogram of the frequencies of different characters
in its input.*/

#define FIRST_CHAR 32 //characters start from here
#define LAST_CHAR 127 // and last till here
#define NUM_CHAR (LAST_CHAR - FIRST_CHAR) + 1 // total ~96

main()
{
  int i;
  int nchars[NUM_CHAR]; 
  for(i = 0; i < NUM_CHAR; ++i)
    nchars[i] = 0;

  int input;
  while( (input=getchar()) != EOF)
    if( (input >= FIRST_CHAR) && (input <= LAST_CHAR) ) 
      ++nchars[input- FIRST_CHAR]; //input minus first char
                                   //will give pos in index.
  int z;
  char A = ' ';                   //a char used
  for(z=0; z < NUM_CHAR; ++z){    //for
    printf("%2c", A);             //printing
    ++A;                          //list of letters

    int counter = 0;              //use a counter to keep track of how many *'s printed
    for(i=0; i < nchars[z]; i++){ 
      if(counter < 70){           //keep printing if less that 70
    printf("*");
    ++counter;}
      else{
    printf(">>>");            //else just print >>> and be done with it
    counter = 0;
    break;}                   //breaks the nearest loop or switch
      }
    printf("\n");}
}

Upvotes: 0

Patashu
Patashu

Reputation: 21793

Two problems.

First problem:

if(c== 'a')
    na++;
if(c== 'b')
    nb++;
if(c== 'c')
    nc++;
if(c== 'd')
    nd++;
else nother++;

This is not one else-if chain, so it can do multiple different things. For example:

If the character is a, it hits the c == 'a' if branch and also the 'it's not c == 'd'' else branch (because a is not equal to 'd', it progresses to the else part and increments nother).

Fix it as follows:

if(c== 'a')
    na++;
else if(c== 'b')
    nb++;
else if(c== 'c')
    nc++;
else if(c== 'd')
    nd++;
else nother++;

Second problem:

for(i==0;i<na;i++){

should of course be

for(i=0;i<na;i++){

Upvotes: 5

Related Questions