1

so the user will input a file with whatever text inside and the program needs to read through each character and count how many there are of each character (uppercase and lowercase letters only). So, there could be 50 of A, 23 of b, etc...

Here's what I have so far in my main.cc:

    char character;
    int i = 65; //this is the iterator to go through upper and lowercase letters
    int count = 0; //counts number of characters and resets when exiting the loop and after using cout
    ifstream file(filename); //filename is a string the user inputs
    while (i != 0) {
        while (file >> character) {
            int a = character;
            cout << a << endl; //testing: outputs the correct number for the letter
            if (i == a) { //but for some reason this part isn't working?
                count++;
            }
        }
        cout << count << endl; //this outputs 0 every time
        count = 0;
        i++;
        if (i == 91)  i = 97;  //switch to lower case
        if (i == 123) i = 0;   //exit loop
    }

I appreciate your help! thanks :)

TheShah1
  • 45
  • 1
  • 7
  • 1
    I think file>> character gives the word not character. So you are actually missing the rest of the characters when you do int a = character. – InQusitive Apr 30 '15 at 17:40
  • 2
    @InQusitive: `character` is of type `char`, so `file >> character` will only read in a single character, not a whole word. – AndyG Apr 30 '15 at 17:41
  • 1
    The problem atm is, you read the file to the end while looking for first Character ('A'), then the filestream has reached EOF! So there wont be any data left in the stream. I would make the condition also while (!file.eof()) – Nidhoegger Apr 30 '15 at 17:42
  • @Andy: Or just an array – Ben Voigt Apr 30 '15 at 17:45
  • Nidhoegger, you're exactly right. It's going through the inside loop just once and it doesn't go back. Now to figure out a different method to do this... – TheShah1 Apr 30 '15 at 17:45
  • @Nidhoegger http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong – Pixelchemist Apr 30 '15 at 17:46
  • @AndyG - I'm supposed to store these into an array of nodes (this is for a homework assignment) and this is only one small part of the assignment – TheShah1 Apr 30 '15 at 17:46
  • Hint: don't pick which letter to work on in advance. Read from the file, and once you have the character, you know which node (from your array) to work on. – Ben Voigt Apr 30 '15 at 17:48
  • @Pixelchemist: Thank you very much. Did not know this yet. – Nidhoegger Apr 30 '15 at 17:48
  • @TheShah1: Either you reopen the file everytime, or you do it all at once, e.g. create an array holding the counts for each letter, then you can go through a switch-case or calculate the array index (pretty easy using ASCII Codes, about two if conditions) and increment the values. Then you need to read the file only once – Nidhoegger Apr 30 '15 at 17:49
  • Do you want 'A' and 'a' to be the same? – Rubix Rechvin Apr 30 '15 at 18:18
  • No, they have to be different. Also, I posted an answer to my own question-- I made it based on the other answers/suggestions here. Thanks everybody – TheShah1 Apr 30 '15 at 18:26
  • *"something is going wrong here..."*.... wow, could you provide ***any*** more detail at all? – abelenky Apr 30 '15 at 18:29

3 Answers3

3

Let's assume that the text is in ASCII or extended ASCII, so that there will be a maximum of 256 possible characters.

You could use an array to hold the number of occurrences of a given character. Each slot would correspond to a character; conversely, the character can be used as an index into the array.

Example:

unsigned int MAXIMUM_CHAR_VALUES = 256U;
unsigned int occurrences[MAXIMUM_CHAR_VALUES] = {0};
char c;
while (my_text_file >> c)
{
  ++occurrences[c];
}
// Print them out
for (unsigned int i = 0; i < MAXIMUM_CHAR_VALUES; ++i)
{
  if (!isprint(i))
  {
    cout << "0x" << hex << i;
  }
  else 
  {
    c = static_cast<char>(i);
    cout << c;
  }
  cout << ":  " << occurrences[i] << "\n";
}

If you must use "nodes" you can change the array to an array of nodes.

There are other structures that can be used, such as a Binary Tree.

Thomas Matthews
  • 52,985
  • 12
  • 85
  • 144
2

This is an ideal place to use a map

read a character from the file

file >> character;

the increment that map location

if( isalpha(character) ) { myMap[character]++; }

At the end, you can iterate through all of the map entries and print them all out.

for(map<char, int >::const_iterator it = myMap.begin(); it != myMap.end(); ++it)
{    
    std::cout << "The character " << it->first << " was found " << it->second<< " times." << std::endl;
}
Rubix Rechvin
  • 561
  • 3
  • 15
  • 1
    I would add a check to determine whether the character is a letter, using `isalpha`, Update the map only if the character is a letter. – R Sahu Apr 30 '15 at 17:54
  • Why would file >> character only get first letter of each word? Just loop it and read the file one character at a time – Rubix Rechvin Apr 30 '15 at 17:56
  • 1
    file >> character reads through every letter. I can test it again to double check. Edit: yeah... it reads through every letter – TheShah1 Apr 30 '15 at 17:59
  • IMO, the `std::map` is overkill. An array, not a vector, is more efficient. The character value can be used as the index into an array of counts. Simple, single access. A map or tree must read a node, decide, read more nodes, then finally increment a value in a node. A lot more work than accessing a slot in an array. – Thomas Matthews Apr 30 '15 at 18:02
  • yeah, map might be a bit of overkill, but it's not as bad as you're stating. The access time of a map is O(log(n)). If we allow n to be 52 (number of total alphabet characters) then this comes out to O(1.7), not horrible. – Rubix Rechvin Apr 30 '15 at 18:05
0

Thanks to the other answers, I came up with this method of doing it... it works perfectly fine so far. Thanks, guys!

char character;
int a[256] = {0};
int i = 65;
ifstream file(filename);

while (file >> character) {
    a[character]++;
}

while (i != 0) {
    character = i;
    cout << "There are " << a[i] << " of " << character << endl;
    i++;
    if (i == 91) i = 97;
    if (i == 123) i = 0;
}
TheShah1
  • 45
  • 1
  • 7
  • The `i == 91` and `i == 123` lines (and `i = 65;`) are inscrutable and poorly written. It would be infinitely clearer to use `if (i == 'Z') i = 'a'; if (i == 'z') i = 0;`, but there are better ways to control the loops than that, too, especially if you don't have to worry about eccentric code sets such as [EBCDIC](http://en.wikipedia.org/wiki/EBCDIC) where the lower-case letters come before the upper-case letters (and both come before the digits). – Jonathan Leffler Apr 30 '15 at 19:41