Program is counting consonants wrong - c++

I'm trying to make a program that counts all the vowels and all the consonants in a text file. However, if the file has a word such as cat it says that there are 3 consonants and 1 vowel when there should be 2 consonants and 1 vowel.
#include <string>
#include <cassert>
#include <cstdio>
using namespace std;
int main(void)
{
int i, j;
string inputFileName;
ifstream fileIn;
char ch;
cout<<"Enter the name of the file of characters: ";
cin>>inputFileName;
fileIn.open(inputFileName.data());
assert(fileIn.is_open());
i=0;
j=0;
while(!(fileIn.eof())){
ch=fileIn.get();
if (ch == 'a'||ch == 'e'||ch == 'i'||ch == 'o'||ch == 'u'||ch == 'y'){
i++;
}
else{
j++;
}
}
cout<<"The number of Consonants is: " << j << endl;
cout<<"The number of Vowels is: " << i << endl;
return 0;
}

Here you check if the eof state is set, then try to read a char. eof will not be set until you try to read beyond the end of the file, so reading a char fails, but you'll still count that char:
while(!(fileIn.eof())){
ch=fileIn.get(); // this fails and sets eof when you're at eof
So, if your file only contains 3 chars, c, a and t and you've read the t you'll find that eof() is not set. It'll be set when you try reading the next char.
A better way is to check if fileIn is still in a good state after the extraction:
while(fileIn >> ch) {
With that in place the counting should add up. All special characters will be counted as consonants though. To improve on that, you could check that the char is a letter:
#include <cctype>
// ...
while(fileIn >> ch) {
if(std::isalpha(ch)) { // only count letters
ch = std::tolower(ch); // makes it possible to count uppercase letters too
if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' || ch == 'y') {
i++;
} else {
j++;
}
}
}

Your program doesn't check for numbers and special characters, as well as uppercase letters. Plus, the .eof() is misused: it gets to the last character of the file, loops again, reads one more character, and only then it realizes it is at the end of the file, generating the extra consonant problem. Consider using while((ch = inFile.get()) != EOF).

I would use a different approach, searching strings:
const std::string vowels = "aeiou";
int vowel_quantity = 0;
int consonant_quantity = 0;
char c;
while (file >> c)
{
if (isalpha(c))
{
if (vowels.find(c) != std::string::npos)
{
++vowel_quantity;
}
else
{
++consonant_quantity;
}
}
}
Note: in the above code fragment, the character is first tested for an alphabetic characters. Characters may not be alphabetical like period or question mark. Your code counts periods as consonants.
Edit 1: character arrays
If you are not allowed to use std::string, you could also use character arrays (a.k.a. C-Strings):
static const char vowels[] = "aeiou";
int vowel_quantity = 0;
int consonant_quantity = 0;
char c;
while (file >> c)
{
if (isalpha(c))
{
if (strchr(vowels, c) != NULL)
{
++vowel_quantity;
}
else
{
++consonant_quantity;
}
}
}

I first thought my very first comment to your question was just a sidenote, but in fact it's the reason for the results you're getting. Your reading loop
while(!(fileIn.eof())){
ch=fileIn.get();
// process ch
}
is flawed. At the end of the file you'll check for EOF with !fileIn.eof() but you haven't read past the end yet so your program enters the loop once again and fileIn.get() will return EOF which will be counted as a consonant. The correct way to read is
while ((ch = file.get()) != EOF) {
// process ch
}
with ch declared as integer or
while (file >> ch) {
// process ch
}
with ch declared as char. To limit the scope of ch to the loop consider using a for-loop:
for (int ch{ file.get() }; ch != EOF; ch = file.get()) {
// process ch;
}
As #TedLyngmo pointed out in the comments, EOF could be replaced by std::char_traits<char>::eof() for consistency although it is specified to return EOF.
Also your program should handle everything that isn't a letter (numbers, signs, control characters, ...) differently from vowels and consonants. Have a look at the functions in <cctype>.

In addition to Why !.eof() inside a loop condition is always wrong., you have another test or two you must implement to count all vowels and consonants. As mentioned in the comment, you will want to use tolower() (by including cctype) to convert each char to lower before your if statement to ensure you classify both upper and lower-case vowels.
In addition to testing for vowels, you need an else if (isalpha(c)) test. You don't want to classify whitespace or punctuation as consonants.
Additionally, unless you were told to treat 'y' as a vowel, it technically isn't one. I'll leave that up to you.
Adding the tests, you could write a short implementation as:
#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
int main (void) {
size_t cons = 0, vowels = 0;
std::string ifname {};
std::ifstream fin;
std::cout << "enter filename: ";
if (!(std::cin >> ifname)) {
std::cerr << "(user canceled input)\n";
exit (EXIT_FAILURE);
}
fin.open (ifname);
if (!fin.is_open()) {
std::cerr << "error: file open failed '" << ifname << "'\n";
exit (EXIT_FAILURE);
}
/* loop reading each character in file */
for (int c = fin.get(); !fin.eof(); c = fin.get()) {
c = tolower(c); /* convert to lower */
if (c=='a' || c=='e' || c=='i' || c=='o' || c=='u')
vowels++;
else if (isalpha(c)) /* must be alpha to be consonant */
cons++;
}
std::cout << "\nIn file " << ifname << " there are:\n " << vowels
<< " vowels, and\n " << cons << " conansants\n";
}
(also worth reading Why is “using namespace std;” considered bad practice?)
Example Input File
$ cat dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
Example Use/Output
$ ./bin/vowelscons
enter filename: dat/captnjack.txt
In file dat/captnjack.txt there are:
25 vowels, and
34 conansants
Which if you count and classify each character gives the correct result.
Look things over and let me know if you have any questions.

I know that the following will be hard to digest. I want to show it anyway, because it is the "more-modern C++"-solution.
So, I will first think and develop an algorithm, and then use moderen C++ elements to implement it.
First to the algorithm. If we use the ASCII code to encode letters, then we will see the following:
We see that the ASCII code for uppercase and lowercase letters just differ in the lower 5 bits. So, if we mask the ASCII code with 0x1F, so char c{'a'}; unsigned int x{c & 0x1F}, we will get values between 1 and 26. So, we can calculte a 5 bit value for each letter. If we now mark all vowels with a 1, we can build a binary number, consisting of 32bits (an unsigned int) and set a bit at each position, where the vowel is true. We then get something like
Bit position
3322 2222 2222 1111 1111 1100 0000 0000
1098 7654 3210 9876 5432 1098 7654 3210
Position with vowels:
0000 0000 0010 0000 1000 0010 0010 0010
This numer can be converted to 0x208222. And if we now want to find out, if a letter (regardless whether upper- or lowercase) is a vowel, then we mask out the not necessary bits from the chararcter ( C & 1F ) and shift the binary number to the right as much position, as the resulting letter code has. If then the bit is set at the LSB position, then we have a vowel. This know how is decades old.
Aha. No so easy, but will work for ASCII coded letters.
Next, we create a Lambda, that will read a string that purely consists of alpha letters and counts the vowels. What is not a vowel, that is a consonant (because we have letters only).
Then we use modern C++ elements to calculate the requested values:
The result is some elegant C++ code with only a few lines.
Please see
#include <utility>
#include <algorithm>
#include <string>
#include <iostream>
#include <fstream>
#include <cctype>
int main() {
// Lambda for counting vowels and consonants in a string consisting of letters only
auto countVowelsAndConsonants = [](std::string& s) -> std::pair<size_t, size_t> {
size_t numberOfVowels = std::count_if(s.begin(), s.end(), [](const char c) { return (0x208222 >> (c & 0x1f)) & 1; });
return { numberOfVowels, s.size() - numberOfVowels }; };
// Inform the user what to do: He should enter a valid filename
std::cout << "\nCount vowels and consonants.\n\nEnter a valid filename with the source text: ";
// Read the filename
if (std::string fileName{}; std::cin >> fileName) {
// Now open the file and check, if it could be opened
if (std::ifstream sourceFileStream(fileName); sourceFileStream) {
// Read the complete source text file into a string. But only letters
std::string completeSourceTextFile{};
std::copy_if(std::istreambuf_iterator<char>(sourceFileStream), {}, std::back_inserter(completeSourceTextFile), std::isalpha);
// Now count the corresponding vowels and consonants
const auto [numberOfVowels, numberOfConsonants] = countVowelsAndConsonants(completeSourceTextFile);
// Show result to user:
std::cout << "\n\nNumber of vowels: " << numberOfVowels << "\nNumber of consonants: " << numberOfConsonants << "\n\n";
}
else {
std::cerr << "\n*** Error. Could not open source text file '" << fileName << "'\n\n";
}
}
else {
std::cerr << "\n*** Error. Could not get file name for source text file\n\n";
}
return 0;
}
Please note:
There are one million possible solutions. Everbody can do, what he wants.
Some people are still more in a C-Style mode and others do like more to program in C++

Related

(C++) Why can't I rely on an extration operator to act as an iterator?

#include <iostream>
#include <fstream>
int main()
{
std::ifstream file("input.txt");
char currentChar;
int charCount = 0;
while (file >> currentChar)
{
charCount++;
if (currentChar == 'a')
{
std::cout << charCount;
}
}
in the above, the charCount that's printed is massively large. If I move charcount into the if statement and turn the input into repetitions of the character 'a', it counts correctly (or would count the number of a's correctly). Is "file >> currentChar" what's causing the charCount number to increment so highly? And if so, what's it doing? Why?
It's not "massively large". You're simply outputting the current count every time you encounter the letter a, and because you don't include any whitespace or newlines, then every number will be joined together and appear like a huge number.
Try this:
std::cout << charCount << std::endl;
And consider doing this just once after the loop. Unless for some reason you want to show all intermediate counts.

How to replace Hi with Bye in a file

I want to replace hi with a bye by reading a file and outputting another file with the replaced letters.
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream myfile;
ofstream output;
output.open("outputfile.txt");
myfile.open("infile.txt");
char letter;
myfile.get(letter);
while (!myfile.eof()) {
if (letter == 'H') {
char z = letter++;
if (z == 'i')
output << "BYE";
}
else output << letter;
}
output.close();
myfile.close();
return 0;
}
My outputs are repeated capital I's that is repeated infinity times.
Here is my input file
Hi
a Hi Hi a
Hi a a Hi
Don't check eof
The eof method is returning the location of the input stream read pointer, and not the status of the get. It is more like telling you whether or not get will succeed, so you could write something like:
while (!myfile.eof()) {
char letter;
myfile.get(letter);
//...
}
In this way, you would at least be getting a new letter at each iteration, and the loop ends when the read pointer reaches the end of the input.
But, there are other cases that might cause the get to not succeed. Fortunately, these are captured by the stream itself, which is returned by get. Testing the status of the stream is as easy as treating the stream as a boolean. So, a more idiomatic way to write the loop is:
char letter;
while (myfile.get(letter)) {
//...
}
Peek at the next letter
When you want to look at the next letter in the input following the detected 'H', you perform an increment.
char z = letter++;
But, this does not achieve the desired result. Instead, it just sets both letter and z variables to the numerical successor of 'H' ('H' + 1), and does not observe the next letter in the input stream.
There is another method you can use that is like get, but leaves the input in the input stream. It is called peek.
char z;
auto peek = [&]() -> decltype(myfile) {
if (myfile) z = myfile.peek();
return myfile;
};
if (peek()) {
//...
}
And now, you can check the value of z, but it is still considered input for the next get on letter.
Close to what you implemented
So, the complete loop could look like:
char letter;
while (myfile.get(letter)) {
if (letter == 'H') {
char z;
auto peek = [&]() -> decltype(myfile) {
if (myfile) z = myfile.peek();
return myfile;
};
if (peek() && z == 'i') {
myfile.get(z);
output << "BYE";
continue;
}
}
output << letter;
}
With this approach, you will be able to correctly handle troublesome cases like HHi as input, or the last letter in the input being an H.
Your two lines:
myfile.get(letter);
while (!myfile.eof()) {
are wrong.
First off you only read letter once, hence your infinite loop.
Secondly you don't use eof in a while loop.
You want something more like:
while (myfile.get(letter)) {
Also:
char z = letter++;
is wrong, you want to read another letter:
myfile.get(z);
but you have to be careful that you get something, so
if(!myfile.get(z)) {
output << letter;
break;
}
So finally:
char letter;
while (myfile.get(letter)) {
if (letter == 'H') {
char z;
if(!myfile.get(z)) {
output << letter;
break;
}
if (z == 'i') {
output << "BYE";
}
else output << letter << z;
}
else output << letter;
}
But now we are consuming the character after any H which may not be desirable.
See #jxh's answer for a way to do this with look ahead.
There is a dedicated function to replace patterns in strings. For example, you could use std::regex_replace. That is very simple. We define, what should be searched for and with what that would be replaced.
Some comments. On StackOverflow, I cannot use files. So in my example program, I use a std::istringstream instead. But this is also an std::istream. You can use any other std::istream as well. So if you define an std::ifstream to read from a file, then it will work in the same way as the std::istringstream. You can simply replace it. For the output I use the same mechanism to show the result on the console.
Please see the simple solution:
#include <iostream>
#include <sstream>
#include <regex>
// The source file
std::istringstream myfile{ R"(Hi
a Hi Hi a
Hi a a Hi)" };
// The destination file
std::ostream& output{ std::cout };
int main() {
// Temporary string, to hold one line that was read from a file
std::string line{};
// Read all lines from the file
while (std::getline(myfile, line)) {
// Replace the sub-string and write to output file
output << std::regex_replace(line, std::regex("Hi"), "Bye") << "\n";
}
return 0;
}

Implementation of word counting on non-text-based file as wc in Linux in C++

I am recently working on implementing word counting as wc in Linux in C++. I've read a lot of posts about how to implement this function, but I've still got a problem. When I use text-based file as the input, it'll return right word counts. Otherwise, it returns incorrect counts. So I am wondering if the logic of my code is wrong. I really can't figure this out. Please help me solve this problem.
What I expected is to get the exact number of word counts as wc does, for example:
wc -w filename
it'll return
wordCounts filename
I want to get the exactly same number of wordCounts as wc does and return as the result of function.
I've used .cpp and .txt files as input, and I got right word count.But when I use .out or other files it returns different result.
Here's my code:
int countWords()
{
std::ifstream myFile(pathToFile);
char buffer[1];
enum states {WHITESPACE,WORD};
int state = WHITESPACE;
int wordCount = 0;
if(myFile.is_open())
{
while(myFile.read(buffer,1))
{
if(!isspace(buffer[0]))
{
if (state == WHITESPACE )
{
wordCount++;
state = WORD;
}
}
else
{
state = WHITESPACE;
}
}
myFile.close();
}
else
{
throw std::runtime_error("File has not opend");
}
return wordCount;
}
It isn't obvious at all, but on a Mac (so it might not apply to Linux, but I expect it does), I can get the same result as wc by using setlocale(LC_ALL, ""): before calling your counting function.
The other problem is, as I noted in a comment, that isspace() takes an integer in the range 0..255 or EOF, but when you get signed values from plain char, you are indexing out of range and you get whatever you get (it is undefined behaviour). Without the setlocale() call, the character codes 9 (tab, '\t'), 10 (newline, '\n'), 11 (vertical tab, '\v'), 12 (formfeed, '\f'), 13 (carriage return, '\r') and 32 (space, ' ') are treated as 'space' by isspace(). When the setlocale() function is called on the Mac, the character code 160 (NBSP — non-breaking space) is also counted as a space, and that brings the calculation into sync with wc.
Here's a mildly modified version of your function which counts lines and characters as well as words. The function is revised to take a file name argument — you may do as you wish with yours, but you should avoid global variables whenever possible.
#include <cctype>
#include <clocale>
#include <fstream>
#include <iostream>
int countWords(const char *pathToFile)
{
std::ifstream myFile(pathToFile);
char buffer[1];
enum states { WHITESPACE, WORD };
int state = WHITESPACE;
int wordCount = 0;
int cc = 0;
int lc = 0;
if (myFile.is_open())
{
while (myFile.read(buffer, 1))
{
cc++;
if (buffer[0] == '\n')
lc++;
if (!isspace(static_cast<unsigned char>(buffer[0])))
{
if (state == WHITESPACE)
{
wordCount++;
state = WORD;
}
}
else
{
state = WHITESPACE;
}
}
myFile.close();
std::cerr << "cc = " << cc << ", lc = " << lc
<< ", wc = " << wordCount << "\n";
}
else
{
throw std::runtime_error("File has not opened");
}
return wordCount;
}
int main()
{
setlocale(LC_ALL, "");
std::cout << countWords("/dev/stdin") << "\n";
}
When compiled (from wc79.cpp into wc79), and run on itself, I get the output:
$ ./wc79 < wc79
cc = 13456, lc = 6, wc = 118
118
$ wc wc79
6 118 13456 wc79
$
The two are now in agreement.

Console input until . and enter

Hello there I have a little problem with cin. How can I do cin while != '.' and '\n' ? Below is my code
#include <stdio.h>
#include <iostream>
using namespace std;
void reverse(char x[])
{
if(*x=='\0')
{
return;
}
else
{
reverse(x+1);
cout<<*x;
}
}
int main(){
char a[]="";
while (cin.get()!='\n'&&cin.get()!='.') {
cin>>a;
}
reverse(a);
}
Input: foo.
Output: .o
It cut me 2 last words
You shouldn't include both "stdio.h" (or better <cstdio>) and <iostream>. The former lets you use C standard IO functions, while the latter is the standard for C++. Pick one, for example as in your code you are actually using some <iostrem> facilities, include that.
The problem you are facing basically requieres 3 steps:
read standard input untill a '.' or a '\n' is entered.
store each character except '.' or '\n'.
send the character read to standard output in reverse order.
I think that second point is the key point. Where do you store the character you read? In your code you seem to use c-style null terminated char arrays, but you are not allocating the necessary memory for doing that.
Then, when you use cin.get() you are actually removing a character from to input stream and you do that 2 times before reading a.
I also don't think that using recursion for the last step is a good idea. Maybe it's mandatory in your assigned task, but use of recursion like this (and the tipical factorial example) better stay in books. If you want to use a stack to accomplish the task, it's better to do so explicitly, like here:
#include <iostream>
#include <stack>
int main() {
char c;
std::stack<char> sc;
while ( std::cin.get(c) && c!='\n' && c!='.' )
sc.push(c);
std::cout << std::endl;
while ( !sc.empty() ) {
std::cout << sc.top();
sc.pop();
}
std::cout << std::endl;
return 0;
}
A more "natural" way of doing this task is to store the chars in a std::string and show them in reverse order:
#include <iostream>
#include <string>
int main()
{
std::string a;
char c;
while ( std::cin.get(c) && c != '.' && c != '\n' )
a += c;
std::cout << std::endl;
// you can print what you read with: std::cout << a;
for ( std::string::reverse_iterator rit = a.rbegin(); rit != a.rend(); ++rit )
std::cout << *rit;
std::cout << std::endl;
return 0;
}
If you want to use an array of char to store the input, you have to preallocate enough memory for your needs.
#include <iostream>
#define MAX_CHARS 128
int main()
{
char a[MAX_CHARS + 1]; // enough to store 128 char and the '\0'
char c;
int counter = 0; // better knowing how many char you read
for ( counter = 0; counter < MAX_CHARS
&& std::cin.get(c) && c!='.' && c!='\n'; counter++ )
a[counter] = c;
a[counter] = '\0';
std::cout << std::endl;
// you can print what you have read with: std::cout << a;
while( counter > 0 ) {
--counter;
std::cout << a[counter];
}
std::cout << std::endl;
return 0;
}
If you are reading input from terminal you have to enter a whole line followed by newline in any case, because you are reading a buffered input. If you need unbuffered input and to stop reading characters right when a . or enter is pressed then there isn't a standard C++ solution, it depends on your environment. For sake of semplicity you can use the c-style (and deprecated) getch():
#include <cstdio>
#include "conio.h"
#define MAX_CHARS 128
int main()
{
char a[MAX_CHARS + 1]; // enough to store 128 char and the '\0'
char c;
int counter = 0; // better know how many char you read
while ( counter < MAX_CHARS && (c=getch())
&& c!='.' && c!='\n' && c!='\r' ) {
putchar(c);
a[counter] = c;
counter++
}
a[counter] = '\0';
printf("\n");
// you can print what you read with: printf("%s\n",a);
while( counter > 0 ) {
--counter;
putchar(a[counter]);
}
printf("\n");
return 0;
}
You can replace the first get with peek:
while (cin.peek() != '\n' && cin.get() != '.')
std::basic_istream::peek keeps the character in the buffer, so std::basic_istream::get reads the same, but compares it to other.
- wrong. That would keep \n in the buffer, but . not.
Right: Use a char variable into which you extract only once and compare it twice:
char c;
while (cin.get(c) && c != '\n' && c != '.')
...
Doing a get removes the character from the input stream, so the first two characters are removed in the while loop condition before you've even entered the loop. cin >> a; reads in the next word (space separated) and puts it into a. It does not read character by character. This puts "o." into a, as 'f'and 'o' have been removed from the input stream. You then read the newline in the condition check and you exit out of the loop.
Instead, you should call cin.get() once and store the return value as an int ready for using it ie.
int ch = cin.get();
while(ch!='\n' && ch != '.') {
// Do something with ch
//get the next character ready for the next iteration
ch = cin.get();
}
I should also mention that a only has enough space for one character. You should make a bigger, doing something like char a[200]; which creates space for 200 characters. You should also check you don't try to access anything past a[199].

Counting occurrences of letter in a file

I'm trying to count the number of times each letter appears in a file. When I run the code below it counts "Z" twice. Can anyone explain why?
The test data is:
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
#include <iostream> //Required if your program does any I/O
#include <iomanip> //Required for output formatting
#include <fstream> //Required for file I/O
#include <string> //Required if your program uses C++ strings
#include <cmath> //Required for complex math functions
#include <cctype> //Required for letter case conversion
using namespace std; //Required for ANSI C++ 1998 standard.
int main ()
{
string reply;
string inputFileName;
ifstream inputFile;
char character;
int letterCount[127] = {};
cout << "Input file name: ";
getline(cin, inputFileName);
// Open the input file.
inputFile.open(inputFileName.c_str()); // Need .c_str() to convert a C++ string to a C-style string
// Check the file opened successfully.
if ( ! inputFile.is_open())
{
cout << "Unable to open input file." << endl;
cout << "Press enter to continue...";
getline(cin, reply);
exit(1);
}
while ( inputFile.peek() != EOF )
{
inputFile >> character;
//toupper(character);
letterCount[static_cast<int>(character)]++;
}
for (int iteration = 0; iteration <= 127; iteration++)
{
if ( letterCount[iteration] > 0 )
{
cout << static_cast<char>(iteration) << " " << letterCount[iteration] << endl;
}
}
system("pause");
exit(0);
}
As others have pointed out, you have two Qs in the input. The reason you have two Zs is that the last
inputFile >> character;
(probably when there's just a newline character left in the stream, hence not EOF) fails to convert anything, leaving a 'Z' in the global 'character' from the previous iteration. Try inspecting inputFile.fail() afterwards to see this:
while (inputFile.peek() != EOF)
{
inputFile >> character;
if (!inputFile.fail())
{
letterCount[static_cast<int>(character)]++;
}
}
The idiomatic way to write the loop, and which also fixes your 'Z' problem, is:
while (inputFile >> character)
{
letterCount[static_cast<int>(character)]++;
}
There are two Q's in your uppercase string. I believe the reason you get two counts for Z is that you should check for EOF after reading the character, not before, but I am not sure about that.
Well, others already have pointed out the error in your code.
But here is one elegant way you can read the file and count the letters in it:
struct letter_only: std::ctype<char>
{
letter_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table()
{
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
std::fill(&rc['A'], &rc['z'+1], std::ctype_base::alpha);
return &rc[0];
}
};
struct Counter
{
std::map<char, int> letterCount;
void operator()(char item)
{
if ( item != std::ctype_base::space)
++letterCount[tolower(item)]; //remove tolower if you want case-sensitive solution!
}
operator std::map<char, int>() { return letterCount ; }
};
int main()
{
ifstream input;
input.imbue(std::locale(std::locale(), new letter_only())); //enable reading only leters only!
input.open("filename.txt");
istream_iterator<char> start(input);
istream_iterator<char> end;
std::map<char, int> letterCount = std::for_each(start, end, Counter());
for (std::map<char, int>::iterator it = letterCount.begin(); it != letterCount.end(); ++it)
{
cout << it->first <<" : "<< it->second << endl;
}
}
This is modified (untested) version of this solution:
Elegant ways to count the frequency of words in a file
For one thing, you do have two Q's in the input.
Regarding Z, #Jeremiah is probably right in that it is doubly counted due to it being the last character, and your code not detecting EOF properly. This can be easily verified by e.g. changing the order of input characters.
As a side note, here
for (int iteration = 0; iteration <= 127; iteration++)
your index goes out of bounds; either the loop condition should be iteration < 127, or your array declared as int letterCount[128].
Given that you apparently only want to count English letters, it seems like you should be able to simplify your code considerably:
int main(int argc, char **argv) {
std::ifstream infile(argv[1]);
char ch;
static int counts[26];
while (infile >> ch)
if (isalpha(ch))
++counts[tolower(ch)-'a'];
for (int i=0; i<26; i++)
std::cout << 'A' + i << ": " << counts[i] <<"\n";
return 0;
}
Of course, there are quite a few more possibilities. Compared to #Nawaz's code (for example), this is obviously quite a bit shorter and simpler -- but it's also more limited (e.g., as it stands, it only works with un-accented English characters). It's pretty much restricted to the basic ASCII letters -- EBCDIC encoding, ISO 8859-x, or Unicode will break it completely.
His also makes it easy to apply the "letters only" filtration to any file. Choosing between them depends on whether you want/need/can use that flexibility or not. If you only care about the letters mentioned in the question, and only on typical machines that use some superset of ASCII, this code will handle the job more easily -- but if you need more than that, it's not suitable at all.