Counting characters

closed account (LEwpfSEw)
I'm currently trying to count the number of specific character a file has and output it out as data but my program counts the letters only up to the letter "s" and then restarts and counts up the letter "t" and begins again.

example of error:
a: 345
b: 342
c: 234
d: 124
a: 345
b: 342
c: 234
d: 124
e: 120
a: 345
b: 342
c: 234
d: 124
e: 120
f: 100

I'm taking in characters from a file that I have in the same directory as the program and I'm using code::blocks 10.05

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <fstream>
#include <cstdlib>

using namespace std;


char add_letter(char,int*);

int main()
{

  int count[26] = {0};

  char filename[50];
  ifstream zelda;
  cin.getline(filename, 50);
  zelda.open(filename);

  if(!zelda.is_open())
  {
      exit(1);
  }

  string message;

  while(! zelda.eof())
  {
      zelda >> message;
      const char *buffer = message.c_str();

      while(add_letter(*buffer++, count));



      for (int i=0; i < 26; i++)
      {
          if (count[i])
          {
              cout << char(i + 'a') << ": " << count[i] << '\n';
          }
      }

  }

  zelda.close();

  return 0;

}

char add_letter(char letter, int count[])
{
    char lowerCaseLetter = tolower(letter);

    if ( lowerCaseLetter >= 'a'&& lowerCaseLetter <= 'z')
    {
        ++count[lowerCaseLetter - 'a'];
    }

    return letter;
}
A couple of different errors here.
First, this code to output the results:
36
37
38
39
40
41
42
      for (int i=0; i < 26; i++)
      {
          if (count[i])
          {
              cout << char(i + 'a') << ": " << count[i] << '\n';
          }
      }

The above is enclosed within the loop which reads a word from the file, thus it is executed many times, rather than just once. That block of code should be moved outside the while loop which starts at line 27.

The second error is the use of .eof()
When this is used, it is almost always an error, and should be avoided. The problem is, the file input command is at line 29, zelda >> message;
Regardless of whether this input fails or succeeds, the remainder of the code in the loop is processed. Only after that is the eof() checked, which is too late.

In this program, if the last word in the file is followed by any whitespace, the last word will be counted twice.

This is the correct way to do it:
1
2
3
4
5
6
7
8
    string message;

    while (zelda >> message)
    {
        const char *buffer = message.c_str();

        while(add_letter(*buffer++, count));
    }


However, that is more complicated than necessary. It can be simplified to this:

1
2
3
4
5
6
  char letter;

  while (zelda >> letter)
  {
      add_letter(letter, count);
  }

It is a bad idea to call function add_letter for each character in the string. It is better to pass the whole string by const reference to the function and within it to count letters.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <fstream>
#include <string>
#include <numeric>
#include <iterator>

int main()
{
	const size_t N = 'Z' - 'A' + 1;
	size_t count[N] = {};

	char filename[50] = {};

	std::cout << "Enter a filename: ";
	std::cin.getline( filename, sizeof( filename ) );

	std::ifstream input_stream( filename );

	if ( input_stream )
	{
		size_t *p = count;
		std::accumulate( std::istreambuf_iterator<char>( input_stream.rdbuf() ),
			std::istreambuf_iterator<char>(), p,
			[=]( size_t *p, char c ) -> size_t *
		        {
				size_t i = toupper( c ) - 'A';
				if ( i < N ) ++p[i];
				return p;
			} );
	}

	for ( size_t i = 0; i < N; i++ )
	{
		if ( count[i] ) std::cout << char( 'A' + i ) << ": " << count[i] << std::endl;
	}
	std::cout << std::endl;
}
Last edited on
closed account (LEwpfSEw)
Hi Chervil, Thank you for your suggestions and on my errors. I will fix them accordingly.

To Vlad from moscow,

could you explain to me lines 21 through 27 of your code? I wish to understand it better on a beginner level. It would be greatly appreciated.

Once again thank you for your guys help.
std:;accumulate is a standard algorithm declared in header <numeric>

You should read its description.
It may help to note that the fourth parameter to std::accumulate (on lines 24-29) is a lambda expression. Before C++11 one would have used a separately defined functor (i.e. function or object that behaves like function).
Topic archived. No new replies allowed.