tags:

views:

208

answers:

4

My program is reading numbers from a file- and it reads the last number twice. What is wrong with my program and what can I do to fix it?

int main()
{

    ifstream inputFile;

    int number = 0; //the input for the numbers in the file
    double total = 0; //the total of the numbers
    double counter = 0;//number of numbers
    double average = 0;//average of the number



    inputFile.open("random.txt");//open file
    if (!inputFile)//test for file open errors
    {
        cout<<"Error \n";
    }



    while (inputFile)
     {
        inputFile >> number ;
        total+=number;
        counter++;
        cout<<"The running total is: " <<total <<"\n";

     }


    total=total*1.00;
    counter=counter*1.00;

    average = total/counter;
    cout<<"\nthe final total is: \t" <<total;
    cout<<"\nthe number of numbers is: \t";
    cout<<counter;
    cout<<"\nthe average of the numbers is: \t";

    cout<<setprecision(8)<< fixed<< average<<"\n";

    inputFile.close();
    return 0;
}

the contents of the file: 42 468 335 501 170 725 479 359 963 465 706 146 282 828 962 492 996 943 828 437 392 605 903 154 293 383 422 717 719 896 448 727 772 539 870 913 668 300 36 895 704 812 323 334 674 665 142 712 254 869 548 645 663 758 38 860 724 742 530 779 317 36 191 843 289 107 41 943 265 649 447 806 891 730 371 351 7 102 394 549 630 624 85 955 757 841 967 377 932 309 945 440 627 324 538 539 119 83 930 542 834 116 640 659 705 931 978 307 674 387 22 746 925 73 271 830 778 574 98 513 987 291 162 637 356 768 656 575 32 53 351 151 942 725 967 431 108 192 8 338 458 288 754 384 946 910 210 759 222 589 423 947 507 31 414 169 901 592 763 656 411 360 625 538 549 484 596 42 603 351 292 837 375 21 597 22 349 200 669 485 282 735 54 1000 419 939 901 789 128 468 729 894 649 484 808 422 311 618 814 515

+6  A: 

This line of code fails when it reaches the end of the file:

inputFile >> number;

but your code doesn't check to see if the stream is still valid until the beginning of the while loop.

Try:

while(inputFile >> number)
{
    total+=number;
    counter++;
    cout<<"The running total is: " <<total <<"\n";
}
Commodore Jaeger
@Commodore Jaeger: when I tried this it only counts up to 100 for some reason, there are 200 numbers in the file
mokwi8
What's the 100th line? Is it a valid integer?
Commodore Jaeger
@ Commodore Jaeger: Yes, I checked, and it is
mokwi8
@mokwi8: Perhaps you had left the read inside the loop too?
Thomas Padron-McCarthy
+2  A: 

I suspect that the boolean test on inputfile (in the while-line) only fails if the eof has actually been read. So the loop will be executed one time too much and number will still have its old value, and therefore be added twice.

See http://www.cppreference.com/wiki/io/eof for an example on how to write a better while loop for reading files. You could do it like this:

while (inputFile >> number)
   {
   total+=number;
   counter++;
   cout<<"The running total is: " <<total <<"\n";
   }
Patrick
+5  A: 

Because the inputFile becomes false1 after an unsuccessful reading attempt has been done, and not when there's just no more data to read. So, when you've read successfully the last element you are inputFile still evaluates to true, and the next iteration of the while is started. Now, at inputFile>>number the failbit is set, but you're not checking it immediately, so your code goes on normally, "thinking" that another element has been read (when actually is just the old one which happened to remain in number).

Quick solution: move the check after the read:

for(;;)
{
    inputFile >> number;
    if(!inputFile)
        break;
    total+=number;
    counter++;
    cout<<"The running total is: " <<total <<"\n";
}

or (better):

while(inputFile >> number)
{
    total+=number;
    counter++;
    cout<<"The running total is: " <<total <<"\n";
}

This works because operator>> returns the stream object, which is evaluated just after the read in the while condition section.


1. I know, I know that it's not actually false but it's operator(void*)... but don't overcomplicate things :)

Matteo Italia
+1  A: 

You've been given one approach. Here's another possibility:

int main() {
    std::ifstream inputFile("random.txt");
    std::vector<int> data;

    std::copy(std::istream_iterator<int>(inputFile),
              std::istream_iterator<int>(),
              std::back_inserter(data));

    double total = (double)std::accumulate(data.begin(), data.end(), 0);
    std::cout << "The final total is: " << total << "\n";
    std::cout << "The number of numbers is: " << data.size() << "\n";
    std::cout << "The average is: " << total / data.size() << "\n";
    return 0;
}

This produces slightly different output (i.e., minus the "running total") but I'm guessing you only added that for debugging.

Jerry Coffin