I have a program that reads from a file, but for some reason it never reaches the end of the file or something, because the loop never ends. I put only 2 lines of text in the file, and a loop like this still ran infinite:

while (! my_file.eof())

Here is the full code:

Implementation:

//-include the DebitCard implementation
#include "Card.h"
//-include the header for I/O
#include <iostream>
//-include header for files
#include <fstream>
#include <string>
//-using definitions
//-used as a shortcut
using std::cout;
using std::cin;
using std::endl;

/**main()
 *-definition of this file
 *-goes in the main method
 *-main method allows the
 *-program to be run
 **/
int main()
{
  DebitCard dc;
  //-char array for filename
  char filename[50];
  //-double for read amount
  double my_double = 0;
  //-char array to hold the information read
  char info[50];
  //-declaration of file object
  ifstream my_file;

  //-prompt the user
  cout << "Enter The File --> ";
  //-get the filename from the user
  cin.getline(filename, sizeof(filename));
  //-open the file based on the input
  my_file.open(filename);

  //-keep count of lines
  int count = 1;
  //-loop while it's no the end of the file
  while (! my_file.eof())
  {
    //-get the line from file
    my_file.getline(info,sizeof(info));
    //-store the value in a double
    //-this must be converted
    my_double = atof(info);
    //-if count is one, then we are on
    //-the first line and it is the balance
    //-to set the debit card to.
    if (count == 1)
    {
      //-print out the balance
      cout << "The Starting Balance Was --> " << my_double << endl;
      //-set the balance
      dc.set_balance(my_double);
    }
    else
    {
      //-variable for what should be withdrew
      double actual_amount = my_double;
      //-call the withdraw method
      dc.withdraw_from(my_double, actual_amount);
      //-if the actual amount withdrew is zero,
      //-then there was a problem
      if (actual_amount == 0)
      {
         //-show the user there was a problme
         cout << "Debit of $" << my_double << " -- Insufficent Funds" << endl;
      }
      else
      {
         //-show the user it was successfull.
         cout << "Debit of $" << my_double << " Completed" << endl;
      }
    }
  }
  //-close the file since we are done
  my_file.close();

  //-print the final balance of the card
  //-use the get_balance() method
  cout << "The Final Balance Is $" << dc.get_balance() << endl;
}

You probably don't need to see the header file I created, but if you need to, then let me know.

>while (! my_file.eof())
That's wrong. The eof member function wasn't designed to be used as a loop condition. Change it to this:

while (my_file.getline(info,sizeof(info)))

Aside from that, there's nothing wrong with your code. It works perfectly on three of my compilers. Trim the code down as much as you can such that the problem still exists. Then give us the trimmed code, a sample file that causes the problem, and details about your OS and compiler.

Haven't I told you that before concerning the exact same problem?

No, this was a different problem. I'm using an older version of bloodshed and it as some really weird lock on files, so once I switched over it worked fine.

Member Avatar for iamthwee

One other thing, if ur using c++ u should try using strings instead of chars - it shud b familiar coming from a java background

And try to avoid !EOF at all costs when reading files, u'll thank me 4 it later.

:rolleyes:

One other thing, if ur using c++ u should try using strings instead of chars - it shud b familiar coming from a java background

It was actually my first choice to use strings. I would MUCH rather use them over char arrays, but all in all it was good practice, I guess. The reason I used char arrays is because it's the only way I could get it to convert to a double. The strod() wouldn't work with strings.

And try to avoid !EOF at all costs when reading files, u'll thank me 4 it later.

Out of curiosity, why do you say that? You and Narue both warned me, but I have no clue why... I thought it was customary to do this. The example I'm reading from actually shows to use !eof.

>The strod() wouldn't work with strings.
Sure it does:

strtod ( s.c_str(), 0 );

I wouldn't recommend using anything but a null pointer for the second argument though. The C-style string produced by c_str() is transient and it's far too easy to invalidate any pointers to it, so you're better off not even trying unless you can quote relevant parts of the standard from memory. :) A better option would be stringstreams:

#include <iostream>
#include <string>
#include <sstream>

template <typename T>
T jsw_strtot ( const std::string& s )
{
  std::istringstream iss ( s );
  T ret;

  iss>> ret;

  return ret;
}

int main()
{
  std::string s = "123.456";
  double d = jsw_strtot<double> ( s );

  std::cout<< d <<'\n';
}

>You and Narue both warned me, but I have no clue why...
The eof flag for a stream is set only after you've tried and failed to read from the stream. So let's say you use this code to read from a file:

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

int main()
{
  std::ifstream in ( "test" );
  std::string s;

  while ( !in.eof() ) {
    std::getline ( in, s );
    std::cout<< s <<'\n';
  }
}

And the contents of the file are:

This
is
a
test

Well, the first three strings are read and printed, just like you expect. However, when getline reads "test", you would expect the loop to stop because it's the last string, right? But it doesn't because getline didn't fail with an end-of-file error, it terminated successfully by reading a line. So the loop continues one more time. This is a classic off-by-one error, and it can be especially frustrating when you end up processing the last record in a file twice.

The solution is to use getline's return value as the condition for the loop. That way when getline does fail, it stops the loop at the right time because if getline fails on end-of-file (or an error), execution won't already be in the body of the loop:

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

int main()
{
  std::ifstream in ( "test" );
  std::string s;

  while ( std::getline ( in, s ) )
    std::cout<< s <<'\n';
}

Now, you can use eof() (or feof()) for a loop condition if you carefully add a kludge to the loop that protects you from the bug, but that's extra work for no real gain.

Member Avatar for iamthwee

It was actually my first choice to use strings. I would MUCH rather use them over char arrays, but all in all it was good practice, I guess. The reason I used char arrays is because it's the only way I could get it to convert to a double. The strod() wouldn't work with strings.


Out of curiosity, why do you say that? You and Narue both warned me, but I have no clue why... I thought it was customary to do this. The example I'm reading from actually shows to use !eof.

I don't really no why EOF is bad i only been learning c for a few weeks. I'll let sum1 else explain but it is to do with if there is an extra newline and the end of the file it sometimes repeats the data.

And I find it difficult to imagine that the string class cannot convert to double, so much so that u have to use chars? Do sum research and i'm sure u will find sumthing good about converting strings to ints and doubles :lol:

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.