Infinite Loop

Read the "before you post" instructions and expect many rude answers. No problem..yes I'm a beginner and this is part of a homework assignment. Also your jobs are safe as I do not want to become a programmer although I am excited learning what I have so far

My issue is when a space is included when prompted for Captains name the program goes into an infinite loop and I do not know why. Here is my code.

#include <iostream>
#include <iomanip>
#include <string>

using namespace std;

int main()
{

//Declare Constant Variables
const double COST_FUEL_POD = 125.50;
const double COST_CASE_AMMO = 17.20;
const double COST_JET_PACK = 99.00;
const double COST_TANK_OXY = 50.40;

cout<<"***************************";
cout<<"***************************"<<endl;
cout<<"Welcome to Space Travel Supplies. \n\n"<<endl;
// Variables to hold quatities of items ordered
int shipID = 0;
int numFuelpod;
int numOfAmmo;
int numJetpacks;
int numOxytanks;
//Declare variables that will hold $$ amounts of items
double fuelPodtotal;
double ammototal;
double jetPacktotal;
double oxyTanktotal;
double total_sales;
string captain_Name;

cout<<"Enter Spaceship ID or -999 to exit: ";
cin>>shipID;

//Use a do...while loop with if...statement to test the expression
do {
if (shipID != -999)
{
cout<<"Enter Captain's Name: ";
cin>>captain_Name;
cout<<"Enter Number of Fuel Pods: ";
cin>>numFuelpod;
cout<<"Enter number of Ammo Cases ";
cin>>numOfAmmo;
cout<<"Enter number of Jetpacks: ";
cin>>numJetpacks;
cout<<"Enter number of Oxygen Tanks: ";
cin>>numOxytanks;
cout<<endl;
cout<<endl;

cout<<left<<"Space Travel Company Sales Statement"<<endl;
cout<<"Spaceship ID Number "<<shipID<<endl;
cout<<"====================================================="<<endl;
cout<<endl;

//Calculations

fuelPodtotal = numFuelpod * COST_FUEL_POD;
ammototal = (numOfAmmo / 100) * COST_CASE_AMMO;
jetPacktotal = numJetpacks * COST_JET_PACK;
oxyTanktotal = numOxytanks * COST_TANK_OXY;
total_sales = fuelPodtotal + ammototal + jetPacktotal + oxyTanktotal;

cout<<setw(15)<<"Cargo "<< setw(20) <<"Sales Amount "<<setw(20)<<"Cost"<<endl;
cout<<setw(15)<<"Fuel Pod "<< setw(20) << numFuelpod << fixed << setprecision(2)<<fuelPodtotal<<endl;
cout<<setw(15)<<"Proton Ammo "<<setw(20)<<numOfAmmo<<fixed<<setprecision(2)<<ammototal<<endl;
cout<<setw(15)<<"JetPacks "<<setw(20)<<numJetpacks<<fixed<<setprecision(2)<<jetPacktotal<<endl;
cout<<setw(15)<<"Oxygen "<<setw(20)<<numOxytanks<<fixed<<setprecision(2)<<oxyTanktotal<<endl;
cout<<"---------------------------------------------------"<<endl;
cout<<setw(35)<<"Total Due: "<<fixed<<setprecision(2)<<total_sales<<endl;
cout<<endl;
}

} while (shipID != -999); {
cout<<"Enter Ship ID: "; }



system("Pause");
return 0;
}
Try "breaking" the operation after you're done with your "do" it will stop the loop, otherwise it will continue while shipID isn't -999 which it doesn't get another chance to prove it isn't
Last edited on
 
cin>>captain_Name;

cin to a string is delimited by any whitespace encountered.
Therefore the second part of the captain's name remained in the input buffer.

Use getline instead.
 
    getline (cin,captain_Name);

http://www.cplusplus.com/reference/string/string/getline/

PLEASE USE CODE TAGS (the <> formatting button) when posting code.
Last edited on
We can work with a smaller example. (It is always good to reduce your problem to the smallest example you can manage while still producing the problem.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <string>

int main()
{
    std::string name ;
    int fuelPods ;

    for ( unsigned i=0; i<3; ++i )
    {
        std::cout << "Enter name: " ;
        std::cin >> name ;

        std::cout << "Fuel pods: " ;
        std::cin >> fuelPods ;
    }
}

Name
> Harvey Wallbanger

Fuel pods
>
Name
>
Fuel pods
>
Name
>
Fuel pods
> Press any key to


So, what happens? When the user is asked to enter a name and enters "Harvey Wallbanger\n", the subsequent cin >> name only extracts the first word, which means that " Wallbanger\n" is still present in the stream when we get to the next extraction operation, which expects a number as input. Obviously what is already in the input stream cannot be stuffed into an int, so the stream goes into an error state. That state is never cleared, so all subsequent extraction operations fail.

Typically when you want to extract a full line of input, spaces and all, you would use std::getline. It extracts a line of text, all whitespace preserved, up to and including the next newline in the input stream. That newline is discarded by the function.

http://www.cplusplus.com/reference/string/string/getline/

So, we might expect the following to work:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <string>

int main()
{
    std::string name ;
    int fuelPods ;

    for ( unsigned i=0; i<3; ++i )
    {
        std::cout << "\nName\n> " ;
        std::getline(std::cin, name) ;

        std::cout << "\nFuel pods\n> " ;
        std::cin >> fuelPods ;
    }
}
Name
> Harvey Wallbanger

Fuel pods
> 30

Name
>
Fuel pods
> 40

Name
>
Fuel pods
> 10


But, as you can see, we only get the opportunity to enter one name. What is this, you're asking? Well, the key is in understanding how the formatted extraction works, and how it interacts with unformatted extraction (such as getline.)

When we did std::cin >> name and entered "Harvey Wallbanger\n" we saw that what was left in the input stream after extraction was " Wallbanger\n". Note that the whitespace after Harvey was left in tact.

When we do std::cin >> fuelPods and enter a number like so: "30\n" what do you think is left in the stream after our extraction? "\n" is. So, when we get back to the top of the loop, our next extraction operation (getline) encounters a newline in the input stream right away. And since it only extracts input up to the first newline it encounters, the string it extracts is empty.

Not quite what we wanted. Fortunately, now that we know what the problem is we can just ignore a character after the last formatted extraction operation that comes before an unformatted extraction operation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <string>

int main()
{
    std::string name ;
    int fuelPods ;

    for ( unsigned i=0; i<3; ++i )
    {
        std::cout << "\nName\n> " ;
        std::getline(std::cin, name) ;

        std::cout << "\nFuel pods\n> " ;
        std::cin >> fuelPods ;
        std::cin.ignore() ;
    }
}
Name
> Harvey Wallbanger

Fuel pods
> 10

Name
> Mellifluer Cadbury

Fuel pods
> 5

Name
> Cassidy Newberg III

Fuel pods
> 3


As you can see, that works. At least as long as the user enters what we expect. Keep in mind that this implementation is still fairly fragile, but it should clue you into what was going on here.
The replies are greatly appreciated. I've attempted both solutions but my program isn't working exactly the way it is supposed to. Ideally it asks for ship id, captain name then quantities of the supplies and as long as -999 isn't entered it performs calculations then SHOULD ask me for another ship ID but it comes back with enter captain's name. I've been committing about 20 hours a week on top of my full time job to this class (online) and still find myself lost most of the time. The instructor puts out the syllabus and that is pretty much it. So it seems I paid a lot of money to learn programming on my own though I assumed I would be taught......No worries, I'll get through it one way or another.

Again thanks for giving me ideas and help!
Thank you Cire! The explanation helped me immensely and I have a better understanding of my program, the mistakes and why the cin.ignore() was needed. Fixed the problem and it works as it is supposed too!
Topic archived. No new replies allowed.