Infinite while loop when trying to read in from file

I am trying to read in from a file to print to the screen but ever since I added system time, the while loop just goes on for infinity. What am I doing wrong?

// Function Definitions

// Function to display menu, display count and user ID, and update value of the
// variable, choice.
void getChoice(int& choice, int& id)
{
cout << right;
static int count = -1;
++count;
cout << setfill(' ') << setw(49) << "________________________________________________" << endl;
cout << "|------------------------------------------------|" << endl;
cout << "|" << setfill(' ') << setw(38) << "Jesse Wood's Fitness Center" << setfill(' ') << setw(11) << "|" << endl;
cout << "|" << setfill(' ') << setw(32) << "Activity System" << setfill(' ') << setw(17) << "|" << endl;
cout << "|" << setfill(' ') << setw(49) << "|" << endl;
cout << "|------------------------------------------------|" << endl;
cout << "|" << setfill(' ') << setw(29) << "MAIN MENU" << setfill(' ') << setw(20) << "|" << endl;
cout << "|" << setfill(' ') << setw(32) << "1) Stationary Bike" << setfill(' ') << setw(17) << "|" << endl;
cout << "|" << setfill(' ') << setw(26) << "2) Treadmill" << setfill(' ') << setw(23) << "|" << endl;
cout << "|" << setfill(' ') << setw(31) << "3) Weight lifting" << setfill(' ') << setw(18) << "|" << endl;
cout << "|" << setfill(' ') << setw(27) << "4) Hatha Yoga" << setfill(' ') << setw(22) << "|" << endl;
cout << "|" << setfill(' ') << setw(38) << "5) Print Transaction Log" << setfill(' ') << setw(11) << "|" << endl;
cout << "|" << setfill(' ') << setw(20) << "6) End" << setfill(' ') << setw(29) << "|" << endl;
cout << "--------------------------------------------------" << endl;
cout << "Your ID is: " << setfill('0') << setw(5) << id << endl;
cout << "Number of hits: " << count << endl << endl;
cout << "Please choose a workout you wish to track, print a log, or end to exit: ";
cin >> choice;
}

//Function to retrieve and validate time, and to update the value of time.
void getTime(int choice, float& time)
{
if (choice == 1 || choice == 2)
{
cout << "Please enter a time: ";
cin >> time;
while (cin.fail() || (time < 30) || (time > 60))
{
cin.clear();
cin.ignore();
cout << "Please enter a valid time (30-60): ";
cin >> time;
}
time = time/60.0;
}
else if (choice == 3)
{
cout << "Please enter a time: ";
cin >> time;
while (cin.fail() || (time < 15) || (time > 30))
{
cin.clear();
cin.ignore();
cout << "Please enter a valid time (15-30): ";
cin >> time;
}
time = time/60.0;
}
else if (choice == 4)
{
cout << "Please enter a time: ";
cin >> time;
while (cin.fail() || (time < 60) || (time > 90))
{
cin.clear();
cin.ignore();
cout << "Please enter a valid time (60-90): ";
cin >> time;
}
time = time/60;
}
}

// Function to generate a random ID and update the value of ID.
void makeId(int& id)
{
srand(time(0));
id = ((rand() % 99999) + 1);
}

// Funtion to validate and update the value of choice.
void verifyChoice(int& choice)
{
while (cin.fail() || (choice > 6) || (choice < 1))
{
cin.clear();
cin.ignore();
cout << "Please enter a valid choice (1-6): ";
cin >> choice;
}
}

// Function to get input for weight.
void getWeight(float& weight)
{
cout << "Please enter a weight: ";
cin >> weight;
while (cin.fail() || (weight > 999) || (weight < 1))
{
cin.clear();
cin.ignore();
cout << "Please enter a valid weight (1-999): ";
cin >> weight;
}
weight = weight/2.2;
}

// Function to calculate calories.
void calculateCals(float& caloriesBurned, float time, float option, float weight)
{
caloriesBurned = (time * option * weight);
}

// Function to calculate intensity.
void getIntensity(float caloriesBurned, string& intensity)
{
if (caloriesBurned <= 200)
{
intensity = "light";
}
else if ((caloriesBurned >= 201) && (caloriesBurned <= 500))
{
intensity = "moderate";
}
else if (caloriesBurned >= 501)
{
intensity = "heavy";
}
}

// Function to print from file.
void printFromFile(fstream& log)
{
int id, choice;
float time, weight, caloriesBurned;
string intensity;
string newChoice = " ";
string timeOf = " ";
log.open("transactionLog.txt", std::fstream::in);
log.clear();
log.seekg(0, std::ios::beg);
while (true)
{
log >> id >> choice >> time >> weight >> caloriesBurned >> intensity >> timeOf;
if (log.eof())
{
break;
}
if (choice == 1)
{
newChoice = "biking";
}
else if (choice == 2)
{
newChoice = "running";
}
else if (choice == 3)
{
newChoice = "lifting";
}
else if (choice == 4)
{
newChoice = "yoga";
}
cout << setfill(' ') << left << setw(10) << id << setw(10) << newChoice << setw(10) << time * 60 << setw(10)
<< weight << setw(10) << caloriesBurned << setw(10) << intensity << setw(10) << timeOf << endl;
}
log.close();
}

// Funtion to read into file.
void storeFile(fstream& log, int id, int choice, float time, float weight, float caloriesBurned, string intensity, string timeOf)
{
log.open("transactionLog.txt", std::fstream::out | std::fstream::app);
log << id << " " << choice << " " << time << " " << weight << " " << caloriesBurned << " " << intensity << " " << timeOf << endl;
log.close();
}

// Function to get system time.
string systemTime()
{
time_t now = time(0);
char* timeOf = ctime(&now);
timeOf[20] = '\0';
return (timeOf);
}

[/code]
This pattern isn't quite right:
1
2
3
4
5
6
7
8
9
10
void verifyChoice(int& choice)
{
    while (cin.fail() || (choice > 6) || (choice < 1))
    {
        cin.clear();
        cin.ignore();
        cout << "Please enter a valid choice (1-6): ";
        cin >> choice;
    }
}

You probably want something like:
1
2
3
4
5
6
7
void verifyChoice(int& choice) {
    do {
        std::cout << "Please enter a valid choice (1-6): ";
        std::cin >> choice;
    }
    while ((choice > 6) || (choice < 1));
}
Hello jw209,


What am I doing wrong?


Many things.

First you have not provided a complete program that can be compiled. Without the include files and "main" it is only a guess at what you are doing and if it is correct.

You refer to an input file, but you have neglected to post what the file contains. Giving everyone the same information to use helps and reduces confusion. Also it shows how the file is laid out. If it is large file a fair usable sample will work.

You are using "float" and this may work, but "double" is the preferred floating point type.

In the function "getChoice" you are overusing the "setfill" and not using ii in the best way that you could.

In several places you use: while (cin.fail() this will work, but while (!cin will do the same thing.

In the function "makeId" you have:
1
2
3
4
5
6
void makeId(int& id)
{
    srand(time(0));

    id = ((rand() % 99999) + 1);
}

First "srand" should be near the beginning of "main" as it only need done once not each time you call the function. A better way to write that is: srand(static_cast<size_t>(time(nullptr)));. Where "size_t" is an alais for "unsigned int".

Then there is the call to "rand". The largest number "rand" is likely to return is 32767, so 32767 % 99999 would leave you with 32767. You could have said id = rand() + 1;. Either would produce the same result. You may want to rethink your mod number. Usually this number is to limit the range of numbers to use.

In the function "printFromFile" you have:
1
2
3
4
5
6
7
string newChoice = " ";
string timeOf = " ";

log.open("transactionLog.txt", std::fstream::in);

log.clear();
log.seekg(0, std::ios::beg);

First when you define a string it is empty and does not need initialized unless you need something there.

Line 4 opens a file or does it? You have not way to know if the file stream is usable.

Lines 6 and 7 do not really do much because if the stream opened the bad bits are already set to (0) zero and there is no reason to reset what is already set. Since the stream is opened for input the file pointer is already at the beginning.

1
2
3
4
5
6
7
8
log.open("transactionLog.txt", std::fstream::in);

if (!log)
{
    std::cout << "\n    Error message\n";

    return 1;
}

The return should get you back to "main" where you can deal with the file not opening and leave the program properly.

Earlier I referred to the function "getChoice". I will need a little to revise that to show you what you could do.

Andy
Hello jw209,

I have had a chance to work on the "getChoice" function;

Look at your code I do not think you are understanding a few points.

Without changing anything the default setting for "std::setfill" is a space. There is no need to put this before every "std::setw". Also the default setting is "std::right".

So until you change one of these settings they will affect every use of "std::setw" in your "cout" statements.

In the following code line 7 and 24 shows you what you need to do if you should change "std::setfill".

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void getChoice(int& choice, int& id)
{
	static int count = -1;
	++count;

	std::cout << std::setfill(' ') << std::setw(49) << "________________________________________________" << std::endl;
	std::cout << std::setfill('_') << std::setw(49) << "_" << std::setfill(' ')  << std::endl;
	std::cout << std::string(49, '_') << '\n';

	std::cout
		<< "|" << std::setw(38) << "Jesse Wood's Fitness Center" << std::setw(11) << "|\n"
		<< "|" << std::setw(32) << "Activity System" << std::setw(17) << "|\n"
		<< "|" << std::setw(49) << "|\n"
		<< "|" << std::string(47, '-') << "|\n"
		<< "|" << std::setw(29) << "MAIN MENU" << std::setw(20) << "|\n"
		<< "|" << std::setw(32) << "1) Stationary Bike" << std::setw(17) << "|\n"
		<< "|" << std::setw(26) << "2) Treadmill" << std::setw(23) << "|\n"
		<< "|" << std::setw(31) << "3) Weight lifting" << std::setw(18) << "|\n"
		<< "|" << std::setw(27) << "4) Hatha Yoga" << std::setw(22) << "|\n"
		<< "|" << std::setw(38) << "5) Print Transaction Log" << std::setw(11) << "|\n"
		<< "|" << std::setw(20) << "6) End" << std::setw(29) << "|\n"
		<< std::string(49, '-') << std::endl;

	std::cout << "Your ID is: " << std::setfill('0') << std::setw(5) << id << std::setfill(' ') << std::endl;
	std::cout << "Number of hits: " << count << '\n' << std::endl;
	std::cout << "Please choose a workout you wish to track, print a log, or end to exit: ";
	std::cin >> choice;
}

Lines 6 - 8 shows you three different ways of doing the same thing. I left them all there to give you an ides of what they output. It looks like this:

 ________________________________________________
_________________________________________________
_________________________________________________
-------------------------------------------------
|           Jesse Wood's Fitness Center         |
|                 Activity System               |
|                                               |
|-----------------------------------------------|
|                    MAIN MENU                  |
|              1) Stationary Bike               |
|              2) Treadmill                     |
|              3) Weight lifting                |
|              4) Hatha Yoga                    |
|              5) Print Transaction Log         |
|              6) End                           |
-------------------------------------------------
Your ID is: 00000
Number of hits: 0

Please choose a workout you wish to track, print a log, or end to exit:



A note: you do not have to use "std::endl;" at the end of every line. The "\n" is enough. There may be a rare occasion when the "\n" does not work and you will have to use "std::endl;", but most of the time I use "std::endl;" on the last line. Also if a "std::cin" follows the last line of a "cout" the "cin" will flush the output buffer before "cin" uses it for input.

I also find that writing the "cout" statement in this way makes it easier to follow and to make changes.

Andy
Topic archived. No new replies allowed.