Tuesday, April 4, 2023

Poor Quality C Programming Examples

 

C is hard enough without low quality programming examples

I recently read through some of the C programming examples from Sanfoundry. Some of the examples are well constructed while others are very poorly constructed.

One of the bad examples I read is found under the heading of Simple C Programs. The example purports to show how to count the number of vowels and consonants in an input sentence.

The source code for the example follows.

/*

 * C program to read a sentence and count the total number of vowels

 * and consonants in the sentence.

 */

#include <stdio.h>

 

void main()

{

    char sentence[80];

    int i, vowels = 0, consonants = 0, special = 0;

 

    printf("Enter a sentence \n");

    gets(sentence);

    for (i = 0; sentence[i] != '\0'; i++)

    {

        if ((sentence[i] == 'a' || sentence[i] == 'e' || sentence[i] ==

        'i' || sentence[i] == 'o' || sentence[i] == 'u') ||

        (sentence[i] == 'A' || sentence[i] == 'E' || sentence[i] ==

        'I' || sentence[i] == 'O' || sentence[i] == 'U'))

        {

            vowels = vowels + 1;

        }

        else

        {

            consonants = consonants + 1;

        }

        if (sentence[i] =='\t' ||sentence[i] =='\0' || sentence[i] ==' ')

        {

            special = special + 1;

        }

    }

    consonants = consonants - special;

    printf("No. of vowels in %s = %d\n", sentence, vowels);

    printf("No. of consonants in %s = %d\n", sentence, consonants);

}

 

This program does not actually identify a sentence. Instead it merely reads a single input line from stdin. The first conditional carefully identifies the values of the vowels and then assumes anything not a vowel is a consonant. A second conditional makes a weak attempt to find “special” characters that are not letters, but this conditional only looks for tabs, spaces and end of string null characters. It completely ignores punctuation and numeric digits. Sentences often contain punctuation and numeric digits, which are neither vowels nor consonants. The error shows in an inflated count of consonants when an input string contains punctuation and/or numeric digits.

The example program is poorly designed and does not fulfill the requirements expressed on the page C Program to Count the Number of Vowels and Consonants in a Sentence - Sanfoundry.

I wrote an Ada program to achieve the same stated goals. This program uses approximately the same number of lines of source code as the C program while avoiding the problem of miscounting consonants.

-- Ada program to read a line of text and count the number of vowels

-- and consonants in the text

 

with Ada.Text_IO; use Ada.Text_IO;

 

procedure Main is

   subtype Letter is Character with

        Static_Predicate => Letter in 'a' .. 'z' | 'A' .. 'Z';

   subtype Vowel is Character with

     Static_Predicate => Vowel in 'a' | 'e' | 'i' | 'o' | 'u' |

       'A' | 'E' | 'I' | 'O' | 'U';

 

   Line       : String (1 .. 80);

   vowels     : Natural := 0;

   consonants : Natural := 0;

   Length     : Natural;

begin

   Put_Line ("Enter a sentence:");

   Get_Line (Item => Line, Last => Length);

   for I in 1 .. Length loop

      if Line (I) in Letter then

         if Line (I) in Vowel then

            vowels := vowels + 1;

         else

            consonants := consonants + 1;

         end if;

      end if;

   end loop;

   Put_Line

     ("Number of vowels in " & Line (1 .. Length) & " is" & vowels'Image);

   Put_Line

     ("Number of consonants in " & Line (1 .. Length) & " is" &

      consonants'Image);

end Main;

 

The Ada program explicitly defines a subtype of Character containing only English letters. It also defines a subtype of Character defining only the vowels defined in the C program.

The first conditional in the Ada program filters out all characters that are not letters. Within that conditional block the current character is tested for being a vowel. If it is not a vowel then it can only be a consonant. Both the vowel count and the consonant count are correct because the program selected only letters and filtered out all non-letter characters.

C language philosophy

The C language expects the programmer to perform all error checking while only providing very primitive means of specifying the correct data conditions. Historically C has concentrated its design on execution speed at the expense of programmer effort.

Ada language philosophy

The Ada language provides syntax tools to define subtypes of a data type based upon either a range of values or set of values. The Ada example above defines two subtypes of the predefined type Character. One subtype defines the set of all lower case and upper case letters. The other subtype defines the set of lower case and upper case letters identified as vowels.

Each of these subtypes is expressed in a very compact manner in a single expression.

These subtypes express exactly what is a letter and what is a vowel.

Conclusion

The C program never specifies what is a letter. The result is a latent error in program logic which most beginning C students would be unlikely to identify. Eliminating this error would require either a laborious list of letters in C or a list of the numeric ranges representing lower case letters and upper case letters. The first option greatly obscures the meaning of the filtering by its complexity. The second option greatly obscures the meaning of the filtering by using the numeric representation of the letters in a compound conditional expression such as

If ((sentence[i] >= 65 && sentence[i] <= 90) || (sentence[i] >= 97 && sentence[i] <= 122))

The Ada equivalent is accomplished by defining the set of values constituting a letter

subtype Letter is Character with

        Static_Predicate => Letter in 'a' .. 'z' | 'A' .. 'Z';

 

Followed by a simple conditional

if Line (I) in Letter then

The Ada “in” operator returns True if Line (I) is a member of the set of values defined for Letter and False if Line (I) is not a member of the set of values define for Letter.

The set of letters is defined as all the characters in the range starting at ‘a’ and ending at ‘z’ and all the characters in the range starting at ‘A’ and ending at ‘Z’. While this set defines the same values as the C conditional example above, it does so in a very clear manner understandable by programmers of all levels of experience, without resorting to a table of values mapping characters to numeric representations.

The Ada program clearly specifies all the values needed to count vowels and consonants, thereby eliminating the latent defect present in the C program.

3 comments:

  1. "y" is a vowel no?

    ReplyDelete
    Replies
    1. nope, just in french, sorry

      Delete
    2. In English 'y' is only sometimes a vowel. For instance, the word "yesterday" contains two 'y's. The first 'y' is not a vowel and the second 'y' is a vowel. The letter 'w' is usually a consonant. It is a vowel only when it teams up with an 'a', 'e', or 'o' to spell a single sound—as in the words draw, few, and low. So the letter 'w' is a vowel only in the two-letter teams 'aw', 'ew', and 'ow'.

      The examples in this blog intentionally simplify the problem to use only vowels that are always vowels in English.

      Delete

Comparison of three algorithms for summing an array of integers

This article shares a comparison of the time taken to sum an array of integers. This article tests three algorithms for summing the array. •...