0

Hi,
I need to count the usage of alphabetical characters in some plain text file. This is what i have came with. Basically just run through the text file and compare each character with the ASCII value of specific searched character.
When I run it, all I can see is just the first printf() string and just error of terminated status when I close the console.
I do have a text.txt file in same folder as the .exe file but I can't see anything.

Not sure if just my syntax is bad or even semantics.
Thx for help! :-)

#include <stdio.h>
#include <stdlib.h>
#define ASCIIstart 65 
#define ASCIIend 90

void main(){
    FILE *fopen(), *fp;
    int c;
    unsigned int sum;

    fp = fopen("text.txt","r");

    printf("Characters found in text: \n");

    for (int i = ASCIIstart; i <= ASCIIend; i++){
        sum = 0;
        c = toupper(getc(fp));
        while (c != EOF){
            if (c == i){
                sum = sum++;
            }
            c = toupper(getc(fp));
        }
        if (sum > 0){
            printf("%c: %u\n",i,sum);
        }
    }
    fclose(fp);
}
schullzroll
  • 114
  • 8
  • If you use the library function `isalpha` you won't have to worry about hard-coding magic numbers, or case. You will need to `#include ` – Weather Vane Oct 19 '17 at 17:24
  • Why are you doing `sum = sum++;`? Don't you think `sum++` would have been enough? – babon Oct 19 '17 at 17:30
  • What magic numbers are you talking about? sorry im a little noob in C programming :/ - Its an habit from school where we have to use this in Pascal – schullzroll Oct 19 '17 at 17:51
  • why are you declaring fopen() ? – Ahmed Masud Oct 19 '17 at 17:55
  • don't you think your for loop should be inside the while loop rather than being outside? – Ahmed Masud Oct 19 '17 at 17:56
  • Its now working, thanks alot for all your help! Now i will just have to figure out what was the main issue, other than me. Thx ! ;-) – schullzroll Oct 19 '17 at 17:56
  • also, perhaps a better method would be to recognize that you have exactly 26 letters in the alphabet :P – Ahmed Masud Oct 19 '17 at 17:56
  • -Ahmed Masud -TBH im not sure what ive done, ive seen it in an online tutorial and just used it, is there any other way? -I dont know, this was my first idea to do it without having to store the value and printing them in alphabetical order :-) in case you though of another solution, im opened to new ideas – schullzroll Oct 19 '17 at 18:00
  • @RollAndSchullz I mean the magic numbers `65` and `90`. ASCII is common but not universal. – Weather Vane Oct 19 '17 at 18:00
  • @WeatherVane yeah but then i would not know what the character is, would i?.. i havent thought much about this problem and as i said, this is the first solution that i came up with, but thanks for the tip :-) – schullzroll Oct 19 '17 at 18:06
  • @AhmedMasud yeah i know how many letters are in alphabet, but using this i can search for various symbols in ASCII – schullzroll Oct 19 '17 at 18:07
  • @RollAndSchullz you would: it is the value read. – Weather Vane Oct 19 '17 at 18:12

6 Answers6

1

Instead of looking up the entire file for each character, you could do

FILE *fp;
int c, sum[ASCIIend - ASCIIstart + 1]={0};
fp = fopen("file.txt,"r");
if(fp==NULL)
{
    perror("Error");
    return 1;
}

int i;
while( (c = toupper(getc(fp)))!= EOF)
{
    if(c>=ASCIIstart && c<=ASCIIend)
    {
        sum[c-ASCIIstart]++;
    }
}
for(i=ASCIIstart; i<=ASCIIend; ++i)
{
    printf("\n%c: %d", i, sum[i-ASCIIstart]);
}

You must check the return value of fopen() to ensure that the file was successfully opened.

There's an array sum which holds the the number of occurrences of each character within the range denoted with ASCIIend and ASCIIstart macros.

The size of the array is just the number of characters whose number of occurrences is to be counted.

sum[c-ASCIIstart] is used because the difference between the ASCII value (if the encoding is indeed ASCII) of c and ASCIIstart would give the index associated with c.

I don't know what you meant with FILE *fopen(), fp; but fopen() is the name of a function in C used to open files.

And by

FILE *fopen(), *fp;

you gave a prototype of a function fopen().

But in stdio.h, there's already a prototype for fopen() like

FILE *fopen(const char *path, const char *mode);

yet no errors (if so) were shown because fopen() means that the function can have any number of arguments. Have a look here.

Had the return type of your FILE *fopen(); were not FILE * or if it were shown to other parameter types like int, you would definitely have got an error.

And, void main() is not considered good practice. Use int main() instead. Look here.

J...S
  • 4,713
  • 1
  • 15
  • 34
1

You can use a character array and parse the file contents with one time traversal and display the array count finally.

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

void main(){
FILE *fopen(), *fp;
int c;
fp = fopen("test.txt","r");
printf("Characters found in text: \n");
char charArr[26]= {0};
c = toupper(fgetc(fp));

while(c!=EOF) {
  charArr[c-'A']=charArr[c-'A']+1;
  c = toupper(fgetc(fp));
}
fclose(fp);
for(int i=0;i<26;i++){
   printf("\nChar: %c | Count= %d ",i+65,charArr[i]);
}
}

Hope this helps!!

MVR
  • 31
  • 2
0

because after first time you are end of the file. and your c = toupper(getc(fp)); returning -1 after that.

0

For counting just one character, you are reading the whole file and repeating this for each and every character. Instead, you can do:

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

#define ASCIIstart 65 
#define ASCIIend 90

int main(){
    FILE  *fp;
    int c, i;
    int alphabets[26] = {0};

    fp = fopen("text.txt","r");
    if (fp == NULL){
        fprintf (stderr, "Failed to open file\n");
        return -1;
    }

    while ((c = toupper(fgetc(fp))) != EOF){
        if (c >= ASCIIstart && c <= ASCIIend)
            alphabets[c - ASCIIstart]++;
    }

    fclose(fp);
    fprintf(stdout, "Characters found in text: \n");
    for (i = 0; i < 26; i++)
        fprintf (stdout, "%c: %d\n", i+ASCIIstart, alphabets[i]);
    return 0;
}
H.S.
  • 9,215
  • 2
  • 10
  • 25
0

TLDR

Working with your code, your loops are inside-out.

I'll answer in pseudo-code to keep the concepts straightforward.

Right now you are doing this:

 FOR LETTER = 'A' TO 'Z': 
      WHILE FILE HAS CHARACTERS
           GET NEXT CHARACTER
           IF CHARACTER == LETTER 
                ADD TO COUNT FOR CHAR
           END IF
      END WHILE
 END FOR

The problem is you are running through the file with character 'A' and then reaching the end of file so nothing gets done for 'B'...'Z'

If you swapped this:

 WHILE FILE HAS CHARACTERS
      GET NEXT CHARACTER 
          FOR LETTER = 'A' TO 'Z'
              IF LETTER = UCASE(CHARACTER)
                   ADD TO COUNT FOR LETTER
              END IF
          END FOR
 END WHILE

Obviously doing 26 checks for each letter is too much so perhaps a better approach.

 LET COUNTS = ARRAY(26) 

 WHILE FILE HAS CHARACTERS
         CHARACTER := UCASE(CHARACTER)
         IF CHARACTER >= 'A' AND CHARACTER <= 'Z'
            LET INDEX = CHARACTER - 'A'
            COUNTS[INDEX]++
         ENDIF
 END WHILE

You can translate the pseudo code to C as an exercise.

Ahmed Masud
  • 19,014
  • 3
  • 28
  • 53
-1

Rewind the pointer to the beginning of the file at the end of your for loop?

This has been posted before: Resetting pointer to the start of file

P.S. - maybe use an array for your output values : int charactercount[pow(2,sizeof(char))] so that you don't have to parse the file repeatedly?

edit: was missing pow()

  • Still not working, i changed ti by adding this at the end of every for cycle... fseek(fp,0,SEEK_SET) but still nothing other than the first printf. And is the way im doing it, without an array, problematic? Can it cause some issues? – schullzroll Oct 19 '17 at 17:42
  • It will make your execution time o(n^2) instead of o(n). Also, if you use an array, you would only need to make one pass. – Alexander Toptygin Oct 19 '17 at 17:57