Home > Software design >  why does only the 1st file reading function executes over multiple programs of the same kind in C la
why does only the 1st file reading function executes over multiple programs of the same kind in C la

Time:10-31

This code contains 3 file handling related functions which read from a file named "mno". But only the 1st called function in the main() is working. If the 1st function of the list is commented then, only the 2nd function will work and the third won't. Same goes for the 3rd one

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

void countVowel(char fin[])
{
  FILE *fl;
  char ch;
  int count = 0;
  fl = fopen(fin, "r");
  while (ch != EOF)
  {
    ch = tolower(fgetc(fl));
    count  = (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') ? 1 : 0;
  }
  fclose(fl);
  printf("Number of Vowels in the file \" %s \"-> \t %d \n", fin, count);
}

void countConsonant(char fin[])
{
  FILE *fl;
  char ch;
  int count = 0;
  fl = fopen(fin, "r");
  while (ch != EOF)
  {
    ch = tolower(fgetc(fl));
    count  = (!(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') && (ch >= 'a' && ch <= 'z')) ? 1 : 0;
  }
  fclose(fl);
  printf("Number of Consonant in the file \" %s \"-> \t %d \n", fin, count);
}

void countAlphabet(char fin[])
{
  FILE *fl;
  char ch;
  int count = 0;
  fl = fopen(fin, "r");
  while (ch != EOF)
  {
    ch = tolower(fgetc(fl));
    count  = (ch >= 'a' && ch <= 'z') ? 1 : 0;
  }
  fclose(fl);
  printf("Number of Alphabets in the file \" %s \"-> \t %d \n", fin, count);
}

int main()
{
  countVowel("mno"); // output -> 10
  countConsonant("mno"); // output -> 0
  countAlphabet("mno"); // output -> 0
  return 0;
}

Here are the contents of "mno" file ->

qwertyuiopasdfghjklzxcvbnm, QWERTYUIOPASDFGHJKLZXCVBNM, 1234567890

CodePudding user response:

As others have mentioned, your handling of EOF was incorrect:

  1. ch was uninitialized on the first loop iteration
  2. Doing tolower(fgetc(fl)) would obliterate the EOF value.
  3. Using char ch; instead of int ch; would allow a [legitimate] 0xFF to be seen as an EOF.

But, it seems wasteful to have three separate functions to create the three different counts because the most time is spent in the I/O versus the determination of what type of character we're looking at. This is particularly true when the counts are so interelated.

We can keep track of multiple types of counts easily using a struct.

Here's a refactored version that calculates all three counts in a single pass through the file:

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

struct counts {
    int vowels;
    int consonants;
    int alpha;
};

void
countAll(const char *fin,struct counts *count)
{
    FILE *fl;
    int ch;
    int vowel;

    count->vowels = 0;
    count->consonants = 0;
    count->alpha = 0;

    fl = fopen(fin, "r");

    if (fl == NULL) {
        perror(fin);
        exit(1);
    }

    while (1) {
        ch = fgetc(fl);

        // stop on EOF
        if (ch == EOF)
            break;

        // we only care about alphabetic chars
        if (! isalpha(ch))
            continue;

        // got one more ...
        count->alpha  = 1;

        ch = tolower(ch);

        // is current character a vowel?
        vowel = (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u');

        // since we know it's alphabetic, it _must_ be either a vowel or a
        // consonant
        if (vowel)
            count->vowels  = 1;
        else
            count->consonants  = 1;
    }

    fclose(fl);

    printf("In the file: \"%s\"\n",fin);
    printf("  Number of Vowels: %d\n",count->vowels);
    printf("  Number of Consonants: %d\n",count->consonants);
    printf("  Number of Alphabetics: %d\n",count->alpha);
}

int
main(void)
{

    struct counts count;
    countAll("mno",&count);

    return 0;
}

For your given input file, the program output is:

In the file: "mno"
  Number of Vowels: 10
  Number of Consonants: 42
  Number of Alphabetics: 52

CodePudding user response:

You are using ch uninitialized. at while (ch != EOF). Every function call after the first has ch equal to 0 at the start, because you forgot to initialize it and the memory was set to -1 before. You can fix it by replacing the loops like this:

int ch;
...
while ((ch = fgetc(fl)) != EOF)
{
    ch = tolower(ch);
    count  = ...;
}

Here ch is getting initialized before you check it and later converted to lowercase.

EDIT:

Note that this only works if ch is an int, so it can handle the value of -1 (EOF) and the byte 255 is not truncated to -1.

EDIT:

At first I said ch was 0 all the time. It was -1. I am so sorry, I swapped it with the null terminator, which is usually the reason for such behavior.

  • Related