Eliminating the Blanks

My solution for this month’s Exercise generated a list of duplicated letters in a string. The list also includes blank lines. It’s possible to prevent the blank lines from being displayed, but to do so requires extra programming kung fu.

For example, here’s the output from the code presented, modified to swallow a longer string:

Enter text: Now is the time for all good men to come to the aid of thier country.
Letter count 9: O
Letter count 8:
Letter count 7: T
Letter count 6: E
Letter count 5:
Letter count 4: I
Letter count 3: H M N R
Letter count 2: A C D F L
Letter count 1: G S U W Y

The letter O appears nine times in the string, E seven, T six. Other letters appear four times, thrice, twice, and once. No letters appear eight or five times, yet those lines appear in the output. While the output is correct, it looks unprofessional. Why not just have output like this instead:

Enter text: Now is the time for all good men to come to the aid of thier country.
Letter count 9: O
Letter count 7: T
Letter count 6: E
Letter count 4: I
Letter count 3: H M N R
Letter count 2: A C D F L
Letter count 1: G S U W Y

This output is cleaner because it doesn’t list letter counts when no letter appears. To generate such clean output you must store the letter counts to ensure that a count value with no letters, such as 8, 7, and 5 in the above examples, is suppressed. For my solution, I chose to add a third array to the program, one that monitors how many letters are counted.

If you haven’t yet reviewed my solution to this month’s Exercise, click here. To fix this code so that it doesn’t show blank lines, I added a new variable, int *v. This pointer serves as a dynamic array to hold the letter counts.

From the original code, int variable max is set to the highest letter count, such as 9 for 'O' in the preceding examples. To keep track of which counts have letters, I use the value of max to create an array for pointer v:

v = (int *)calloc(max,sizeof(int));

The calloc() function allocates storage and initializes each element to zero. In this statement, v is set to the address of an “array” of integer storage locations equal to the value of max, like int v[max] (if that were possible).

To determine which characters are repeated at given values, 0 to max, I use nested for loops:

for(x=max;x>0;x--)
        {
            for(y=0;y<26;y++)
            {
                if(alphabet[y]==x)
                    *(v+x) = 1;
            }
        }

Say the most repeated letter is 'O' and the value of max is 9. The outer for loop wends from max down to zero. The inner for loop scans array alphabet[] to look for any matches for character counts equal to x. When a match is found, such as 'O', value 1 (TRUE) is set for the array element: *(v+x)=1 is the same as v[x]=1.

For the opposite condition, if no characters equal a count of 8, and the alphabet[] array scan doesn’t show a 7 in any element position, the v pointer “array” retains its original value of zero.

After the v array is filled, indicating which values have characters, the second set of nested for loops display the program’s output but artfully skips over any values without characters:

    /* display duplicated character counts */
    for(x=max;x>0;x--)
    {
        if( *(v+x) )    /* ensure only counts with letters are shown */
        {
            printf("Letter count %d:",x);
            for(y=0;y<26;y++)
                if(alphabet[y]==x)
                    printf(" %c",y+'A');
            putchar('\n');
        }
    }

The test if(*(v+x)) determines if a given character count from “array” v is 1 or 0, TRUE or FALSE. if true, the duplicated letters are displayed. Otherwise, no output appears.

I suppose other ways are available to skip non-informative rows in output, but I can’t see any way of processing the data without scanning twice.

Leave a Reply