Print a Histogram based on word lengths (C)

Viewed 19002

This is a K&R exercise (1-13)...

"Write a program to print a histogram of the length of words in its input. It is easy to draw the histogram with bars horizontal; a vertical orientation is more challenging."

The section was about arrays, and to be honest, I'm not sure I fully understood it. Everything up to this point was fairly easy to grasp, this was not.

Anyway I'm trying to do a histogram with horizontal bars first. Once I got that down I'll try vertical, but right now I'm not even sure where to begin with the easy version. (I slept on it, woke up, and still couldn't get it.)

I drew an example of what the program would output:

----------------------------------------------------------------
001|XX
002|XXXX
003|X
004|XXXXXXXXXX
005|XXXXXXXXXXXXXXXXXXXXXXXXX
006|XXXX
007|X
008|
009|XXXXXXXXX
010|XXX
>10|XXXX
----------------------------------------------------------------

And tried to break it (the program) down in sections. This is what I came up with:

  1. PRINT TOP BORDER
  2. PRINT CATEGORY, PRINT X EACH TIME CONDITION IS TRUE, PRINT NEWLINE, REPEAT.
  3. PRINT BOTTOM BORDER

But the more I think about it the less I think that's how it would work (because getchar() goes through one character at a time, and it wouldn't be able to go back up to put a X in the right category.) Or...

... I'm just really confused as to how I would solve this problem. Here's as far as I've been able to get code wise:

#include <stdio.h>

#define MAXWORDLENGTH 10

// print a histogram of the length of words in input. horizontal bar version

int main(void)
{
  int c;
  while ((c = getchar()) != EOF) {

  }

  return 0;
}

Could someone help enlighten me? Not necessarily with the code, maybe just pseudo code, or with some "words from the wise" as to what I need to do, or think, or something. This has just been a really big stone in the road and I'd like to get past it :/.

(I'll check back in 30 minutes)

18 Answers
//This is for horizontal histogram.
//It works for any number of lines of words where total words <= MAX
#include <stdio.h>
#define MAX 100 //Change MAX to any value.But dont give words more than MAX.

void main()
{
    int w, nwords[MAX] = {0}, i = 0;   //nwords is an array for storing length of each word.Length of all words initialized to 0.

    while ((w = getchar()) != EOF)
    {
        if (w == ' ' || w == '\t' || w == '\n')
            ++i;            //if space or tab or newline is encountered, then index of array is advanced indicating new word
        else
            ++nwords[i];        //increment the count of number of characters in each word
    }       //After this step,we will have array with each word length.

    for (i = 0; i < MAX; i++)   //iterating through array
    {
        printf("\n");
        for (; nwords[i] > 0; nwords[i]--)  
            printf("$");        //if length of word > 0 , print $ and decrement the length.This is in loop.
        if (nwords[i+1] == 0)   //as MAX is 100, to avoid printing blank new lines in histogram,we check the length of next word.
            break;              //If it is 0, then break the loop
        printf("\n");   //After each word bar in histogram, new line.
    }
    printf("\n");
} //main

I've been also studying K&R book. An good approach is to use a int array for storing word frequencies. The array index is the word length, and the array values are the frequencies.

For example:

int histogram[15]; // declares an int array of size 15

// it is very important to initialize the array
for (int i = 0; i <= 15; ++i) {
    histogram[i] = 0;
}

histogram[4] = 7; // this means that you found 7 words of length 4

Given that now you have a data structure for storing your word length frequencies, you can use the same reasoning of Word Counting example found in the book to populate the histogram array. It is very important that you manage to find the right spot for word length tracking (and resetting it) and histogram update.

You can create a function display_histogram for displaying the histogram afterwards.

Here's a code example:

#include<stdio.h>

#define MAX_WORD_LENGTH 15
#define IS_WORD_SEPARATOR_CHAR(c) (c == '\n' || c ==  ' ' || c == '\t')

#define IN  1
#define OUT 0

/* WARNING: There is no check for MAX_WORD_LENGTH */

void display_horizontal_histogram(int[]);
void display_vertical_histogram(int[]);
void display_histogram(int[], char);

void display_histogram(int histogram[], char type) {
    if (type == 'h') {
        display_horizontal_histogram(histogram);
    } else if (type = 'v') {
        display_vertical_histogram(histogram);
    }
}

void display_horizontal_histogram(int histogram[]) {
    printf("\n");

    //ignoring 0 length words (i = 1)
    for (int i = 1; i <= MAX_WORD_LENGTH; ++i) {
        printf("%2d: ", i);
        for (int j = 0; j < histogram[i]; ++j) {
            printf("*");
        }
        printf("\n");
    }

    printf("\n\n");
}

void display_vertical_histogram(int histogram[]) {
    int i, j,  max = 0;

    // ignoring 0 length words (i = 1)
    for (i = 1; i <= MAX_WORD_LENGTH; ++i) {
        if (histogram[i] > max) {
            max = histogram[i];
        }
    }


    for (i = 1; i <= max; ++i) {
        for (j = 1; j <= MAX_WORD_LENGTH; ++j) {
            if (histogram[j] >= max - i + 1) {
                printf("  * ");
            } else {
                printf("    ");
            }
        }
        printf("\n");
    }

    for (i = 1; i <= MAX_WORD_LENGTH; ++i) {
        printf(" %2d ", i);
    }

    printf("\n\n");
}

int main()
{
    int c, state, word_length;
    int histogram[MAX_WORD_LENGTH + 1];

    for (int i = 0; i <= MAX_WORD_LENGTH; ++i) {
        histogram[i] = 0;
    }

    word_length = 0;
    state = OUT;
    while ((c = getchar()) != EOF) {
        if (IS_WORD_SEPARATOR_CHAR(c)) {
            state = OUT;
            if (word_length != 0) {
                histogram[0]++;
            }
            histogram[word_length]++;
            word_length = 0;
        } else {
            ++word_length;
            if (state == OUT) {
                state = IN;
            }
        }
    }

    if (word_length > 0) {
        histogram[word_length]++;
    }

    display_histogram(histogram, 'h');
    display_histogram(histogram, 'v');
}

Here's an input/output sample:

kaldklasjdksla klsad lask dlsk aklsa lkas  adç  kdlaç kd dklask las kçlasd kas kla sd saçd sak dasças  sad sajçldlsak dklaa slkdals kkçl askd lsak lçsakç lsak lsak laskjl sa jkskjd aslld jslkjsak dalk sdlk jsalk askl jdsj dslk salkoihdioa slk sahoi hdaklshd alsh lcklakldjsalkd salk j  sdklald jskal dsakldaksl daslk

 1: *
 2: ***
 3: ******
 4: ***************
 5: **********
 6: ****
 7: ****
 8: ***
 9: 
10: *
11: **
12: 
13: 
14: **
15: 


              *                                             
              *                                             
              *                                             
              *                                             
              *                                             
              *   *                                         
              *   *                                         
              *   *                                         
              *   *                                         
          *   *   *                                         
          *   *   *                                         
          *   *   *   *   *                                 
      *   *   *   *   *   *   *                             
      *   *   *   *   *   *   *           *           *     
  *   *   *   *   *   *   *   *       *   *           *     
  1   2   3   4   5   6   7   8   9  10  11  12  13  14  15 

Here is the example of simple vertical Histogram

#include <stdio.h>

int main()
{
    int c, i, j, max;
    int ndigit[10];

    for (i = 0; i < 10; i++)
        ndigit[i] = 0;

    while ((c = getchar()) != EOF)
        if (c >= '0' && c <= '9')
            ++ndigit[c-'0'];

    max = ndigit[0];
    for (i = 1; i < 10; ++i)        /* for Y-axis */
        if (max < ndigit[i])
            max = ndigit[i];

    printf("--------------------------------------------------\n");
    for (i = max; i > 0; --i) {
        printf("%.3d|", i);
        for (j = 0; j < 10; ++j)
            (ndigit[j] >= i) ? printf(" X ") : printf("   ");
        printf("\n");
    }
    printf("   ");
    for (i = 0; i < 10; ++i)        /* for X-axis */
        printf("%3d", i);
    printf("\n--------------------------------------------------\n");
    return 0;
}
#include <stdio.h>
#include <string.h>

int main()
{
    //hold length of string
    unsigned long length;
    // Holds the name input by user upto 50 characters
    char name[50];
    //iterator for generating dash for bar chart
    int i = 0;
    //iterator for generating dash for bar chart
    int j = 0;
    //take user name input
    printf("input your name [without spaces and < 50 characters] : ");
    scanf("%s", &name[0]);
    //find the length of string
    length = strlen(name);
    printf("length of your name is %lu \n", length);
    //generate dashes for bar chart
    while (i < length)
    {
        printf("--");
        ++i;
    }
    printf("| \n");
    // fill the bar chart with []
    while (j < length)
    {
        printf("[]");
        ++j;
    }
    printf("| \n");
    //generate dashes for bar chart
    while (length > 0)
    {
        printf("--");
        --length;
    }
    printf("| \n");
}

input your name [without spaces and < 50 characters] : ThisIsAtestRun

length of your name is 14

----------------------------|
[][][][][][][][][][][][][][]|
----------------------------|

I've tried to implement the latter part of the question (i.e. Displaying the histogram in a vertical manner) and have managed to get most of it done. In the code below, The maximum number of words accepted are 20 and the maximum word length is 10. Also, apologies for not getting the best graphical representation of a typical histogram but the logic to display vertical bars is completely accurate! Here's my code,

#define MAXWORDS 20
#define MAXLENGTH 10

int c, nlength = 0, i, nword = 0, j;
    int length_words[20]= {0};

    while((c = getchar()) != EOF && nword <= MAXWORDS)
    {
        if(c != ' ' && c != '\t' && c != '\n')
            ++nlength;
        else
        {
            if(nlength != 0){
                length_words[nword] = nlength;
                ++nword;
               /* for(i = 0; i < nlength; i++)
                printf("O");
                printf("\n");*/
                printf("Word number: %d has length: %d\n", nword - 1, nlength);
            }
            nlength = 0;
        }
    }
    // Displaying the Histogram
    for(i = MAXLENGTH; i > 0; i--)
    {
        for(j = 0; j < nword; j++)
        {
            if(i > length_words[j])
                printf("   ");
            else
                printf(" O ");
        }
        printf("\n");
    }

Feel free to run this and let me know in case of any discrepancy or loopholes!

#include <stdio.h>

int main(void)
{
int i, ii, state, c, largest, highest;
int A[100];
for(i = 0; i < 100; ++i)
    A[i] = 0;
i = ii = state = c = largest = 0;

while((c = getchar()) != EOF)
{
    if(c == ' ' || c == '\b' || c == '\n')
    {
        if(state)
        {
            ++A[i];
            if(largest <= i)
                largest = i;
            i = state = 0;
        }
    }
    else
    {
        if(state)
            ++i;
        else
            state = 1;
    }
}
for(i = 0; i < 100; ++i)
    if(highest <= A[i])
        highest = A[i];

for(i = 0; i <= highest; ++i)
{
    for(ii = 0; ii < 100; ++ii)
        if(A[ii])
        {
            if(A[ii] > (highest - i))
                printf("*\t");
            else
                printf(" \t");
        }
    putchar('\n');
}
for(ii = 0; ii < 100; ++ii)
    if(A[ii])
        printf("-\t");
putchar('\n');

for(ii = 0; ii < 100; ++ii)
    if(A[ii])
        printf("%d\t", ii + 1);
putchar('\n');
return 0;
}

Print Histogram based on word Length. (C Program).

HORIZONTAL VERSION :

#include<stdio.h>
#define MAX 15

int main()
{
    int c, wordLength, count;
    int arr[MAX] = { 0 };
    
    wordLength = count = 0;
    
    while((c = getchar()) != EOF)
    {
        if(c != ' ' && c != '\t' && c != '\n')
            ++arr[count];
        else
            ++count;
    }
    
    for(int i = 0; i <= count; i++)
    {
        printf("\n%2d |", i+1);
        
        for(int k = arr[i]; k > 0; k--)
            printf("— ");
    }
    
    return 0;
}

Input/Output :

man in black thor jsjsk ksskka
 1 |— — —
 2 |— —
 3 |— — — — —
 4 |— — — —
 5 |— — — — —

VERTICAL VERSION :

#include<stdio.h>
#define MAX 15

int main()
{
    int c, count, maxLength;
    int arr[MAX] = { 0 };
    
    maxLength = count = 0;
    
    while((c = getchar()) != EOF)
    {
        if(c != ' ' && c != '\t' && c != '\n')
            ++arr[count];
        else
            ++count;
        
        if(arr[count] > maxLength)
            maxLength = arr[count];
    }
    
    for(int i = 1; i <= maxLength + 2; i++)
    {
        printf("\n");
        for(int k = 0; k <= count; k++)
        {
            if(i <= maxLength)
            {
                if(maxLength - i < arr[k])
                    printf("|");
                else
                    printf(" ");
            }
            else
            {
                if(maxLength - i == -1)
                    printf("—");
                else
                    printf("%d", k+1);
            }
            
            printf(" ");
        }
        
    }
    
    return 0;
}

Input/Output :

jsjs sjsj sjsj sjskks sjs sjs
      |
      |
| | | |
| | | | | |
| | | | | |
| | | | | |
— — — — — —
1 2 3 4 5 6

here is the method that I used :

#include <stdio.h>

#define MAXWD 25 // maximum words 
#define MAXLW 20 // maximum lenght of word or characters

int     main(void) {
    int word[MAXWD]; // an array consists of 25 words 
    int c, i, j, nc, nw; // declaring c for the input, i for the loop 'for', j is for printing left to right, nc and nw stands for new character and new word

    for (i = 0; i < 25; ++i)
            word[i] = 0;

    nc = nw = 0; // set to count from 0

    while ((c = getchar()) != EOF) {

            ++nc;
            if ( c == ' ' || c == '\t' || c == '\n') {

                    word[nw] = nc -1; // for deleting the space to go for the new word

                    ++nw;
                    nc = 0; // start counting from zero
            }
    }
    for (i = MAXLW; i >= 1; --i) {
            for(j = 0; j <= nw; ++j) { // to start from left to wright
                    if (i <= word[j]) // MAXLW is less  or equal to the number of words
                            putchar('|');
                    else
                            putchar(' ');
            }
            putchar ('\n');
    }
    return 0;
}
Related