tags:

views:

329

answers:

7

Can sommebody please tell me what is not right about this code? It compiles and everything great but the output is solid zero's all the way down. So it is not counting the letters.

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

const char FileName[] = "c:/test.txt";

int main () 
{
    string lineBuffer;
    ifstream inMyStream (FileName); //open my file stream


    if (inMyStream.is_open()) 
    {
       //create an array to hold the letter counts
       int upperCaseCount[26] = {0};
           int lowerCaseCount[26] = {0};

       //read the text file
       while (!inMyStream.eof() )
       {
        //get a line of text
           getline (inMyStream, lineBuffer);
           //read through each letter in the lineBuffer
           char oneLetter;
           for( int n=0; n < (int)lineBuffer.length(); ++n )
        {
       oneLetter = char( lineBuffer[n] ); //get a letter
                if (oneLetter >= 'A' && oneLetter <='Z') 
       { //decide if it is a capital letter
                     upperCaseCount[int(oneLetter)- 65]++; //make the index match the count array
                         if (oneLetter >= 'a' && oneLetter <='z') 
          { //decide if it is a lower letter
                               lowerCaseCount[int(oneLetter)- 65]++; //make the index match the count array
                         }//end 
                }//end
        }
        }//end of while

        inMyStream.close(); //close the file stream

        //display the counts
        for (int i= 0; i < 26; i++)
            cout << char(i + 65) << "\t\t" << lowerCaseCount[i] << char(i + 95) << "\t\t" << lowerCaseCount[i] << endl;
}//end of if
        else cout << "File Error: Open Failed";

       return 0;
}
+6  A: 

EDIT: Indeed the problem described here is not the only one, see the other answers for more complete solutions.

upperCaseCount[int(oneLetter)- 65]++; //make the index match the count array
                     if (oneLetter >= 'a' && oneLetter <='z') 
                                     { //decide if it is a lower letter
                           lowerCaseCount[int(oneLetter)- 65]++;

(At least) one of these two 65 is wrong. I would recommend int('A') and int('a') instead...

Note: this is probably not what explains your problem.

Pascal Cuoq
Good catch! The lowercase letters start at 97, if I remember correctly.
Carl Smotricz
+1, but it's just 'a' or 'A', no `int()` around it.
Michael Krelin - hacker
Ah, well, he probly means to be casting, i.e. (int) ('A').
Carl Smotricz
I had not noticed the C++ tag so I was aping the syntax of `int(oneLetter)` nearby. I don't seem to get the hang of C++ casts, though (now that I know it's C++).
Pascal Cuoq
The thing is - 'a' *is* an int with no casts. And conventional C cast is (int)'a' anyway ;-)
Michael Krelin - hacker
@hacker:in C, a character constant has type int, but in C++ it has type char. If you overload `f()` for both char and int, `f('a')` will call the char overload.
Jerry Coffin
+2  A: 

Your if concerning upper and lower case letters are incorrectly nested. You don't even look at lowercase letters if oneLetter is not uppercase. Those two ifs should be at the same level.

That's the only error I can see.

I'd recommend either debugging, as gf suggests, or throwing in some print statements to verify your assumptions about what's happening (or not).

Carl Smotricz
+4  A: 

You just have your if statement scoping wrong here. Each letter can be either uppercase or lowercase, but the way your if statements are scoped, you're only checking for lowercase if the letter is already uppercase, which of course is nonsensical.

You want something more like:

for(unsigned n = 0; n < lineBuffer.length(); ++n)
{
   oneLetter = char( lineBuffer[n] ); // get a letter
   if (oneLetter >= 'A' && oneLetter <='Z') {
     upperCaseCount[int(oneLetter)- 'A']++;
   }
   else if (oneLetter >= 'a' && oneLetter <='z') { 
     lowerCaseCount[int(oneLetter)- 'a']++;
   }
}
Charles Salvia
Thanks guys works perfect like a charm You all are wonderful. Hang around I 've got two more assignments due by the end of tonight. LOL!
LilProblems
+1  A: 

There could be other things wrong with this code, but one thing that stands out is that the if statement that counts the lower case letters is inside the if statement that counts the upper case statement. Your test file probably does not contain any upper case letters, and hence the output is a solid zero.

There should be two separate if statements, like:

if (oneLetter >= 'A' && oneLetter <='Z') 
{ //decide if it is a capital letter
  upperCaseCount[int(oneLetter)- 65]++; //make the index match the count array   
}//end

if (oneLetter >= 'a' && oneLetter <='z') 
{ //decide if it is a lower letter
  lowerCaseCount[int(oneLetter)- 65]++; //make the index match the count array
}//end
Faraz
@Faraz:The logic of your second if statement does *not* match the comment (at least with any character set I know of). You're subtracting `65` whether the letter is upper case or lower case, but 'a' and 'A' clearly don't have the same value...
Jerry Coffin
There should be one if statement, use `toupper` or `tolower` to convert the character then compare. Also, get rid of the Magic Number 65, replace with 'A'.
Thomas Matthews
Edit: My bad, the original post contained two `if` statements for distinguishing between upper and lower case. I still stand by replacing 65 with 'A' or 'a'.
Thomas Matthews
+7  A: 

You've gotten some help with the problem you knew you had, now perhaps a bit with one you may not realize you have (yet):

   while (!inMyStream.eof() )
   {
       //get a line of text
       getline (inMyStream, lineBuffer);

One thing you should learn right away is that as you've written it, this won't work correctly. What you normally want to do is:

while (getline(inMyStream, lineBuffer)) {
    // .. the rest of the processing.

However, since you're only processing one character at a time, and ignoring everything but letters, it would probably be simpler to only read one character at a time:

int ch;
while (inMyStream >> ch)
// process the character

Since nobody else has mentioned them, I'll also point out that instead of explicitly testing against 'a' and 'z' to find lowercase letters, and 'A' and 'Z' to find upper case, you'd be better off using islower and isupper, which are supplied in <ctype.h> (among a couple of other places):

#include <ctype.h>

while (inMyStream >> ch)
    if (isupper((unsigned char)ch))
        ++upperCount[(unsigned char)ch-'A'];
    else if (islower((unsigned char)ch))
        ++lowerCount[(unsigned char)ch-'a'];
Jerry Coffin
In this assignment I was given the code already I just had to modify it to count lowercase as well as uppercase.We are not supposed to change any of the code that was given. I know - that sucks huh?
LilProblems
Pity you couldn't change code, because it would certainly be a lot simpler to have one loop that creates counts for *all* characters, then just print out the upper and lower case letters. Try it and see how much complexity is removed!
Tony van der Peet
A: 

How about the printout at the end, where lower case letter counts are printed twice? This explains why it's "zeroes all the way down", because the original code was counting the upper case letters correctly wasn't it?

Tony van der Peet
A: 

OK, I couldn't resist. Here is a way to make your life easier: For ASCII character set, declare an array of 256 elements.

Use the raw character read as an index into the array and increment the value.
After the analysis, you can sum the locations 'A' (yes, as the index) through 'Z' and likewise for lowercase.

char text_char;
//...
// inside input loop
  ++letter_count[text_char];

// Summing up things...
for (unsigned int sum = 0, index = 'A';
    index <= 'Z';
    ++index)
{
   sum += letter_count[index];
}

The point here is that the char data type can be used as an index into an array; no need to cast to int.

Yes, I may get chastised for providing code to a homework problem.

Thomas Matthews