Why does the program loop infinitely? - c++

How to input a string of charaters like "Peter Johnson"?
My program only reads 1 single name, if I put a space, the program loops infinitely
Writting John, works, but the space character makes it loop. Why is that? Also I know the program might not be completely finished.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int x=0;
char name [25];
float paycheck;
cout<<"WELCOME TO THE EMPLOYEE SALARY GENERATION PROGRAM\n\n";
while (x!=-1)
{
cout<<"Enter employee name or -1 to stop the program\n";
cin>>name;
cout<<"Enter employee code (1=manager, 2=worker, 3=comission, 4=pieceworker) or -1 to stop the program\n";
cin>>x;
switch (x)
{
case 1:
cout<<"Your weekly total paycheck is 2 500 $\n"; // FIXED weekly manager's salary
break;
case 2: // 8.50 per hour + over time for workers
cout<<"Please enter the amount of hours worked\n";
cin>>paycheck;
if(paycheck<40)
paycheck=paycheck*8.50;
else
paycheck= (paycheck-40)*8.50 +(40*8.50);
cout<<name<<"'s paycheck is "<<paycheck<<"$\n";
break;
case 3: // comission workers make 250 + 5.7% of their weekly sales
cout<<"Please enter amount of weekly sale made\n";
cin>>paycheck;
paycheck = paycheck*5.7/100 + 250;
break;
case 4: // pieceworkers make 50$ per item produced
cout<<"Please enter the number of items produced this week\n";
cin>>paycheck;
paycheck = paycheck*50;
cout<<"The employee"<<name<<"Made"<<paycheck<<"$ this week";
break;
default:
break;
}
}
system ("PAUSE");
}

The 'cin' function stops reading when it finds a space. Use 'getline' to read the names.
EDIT: Debug the code, and added some safe measures to avoid program crashing due to bad input.
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
float foo()
{
float fl = 0.0f;
string str;
while(true) {
getline(cin, str);
stringstream sstream(str);
if (sstream >> fl)
break;
cout << "Invalid Input" << endl;
}
return fl;
}
int main()
{
string x;
string name;
char number = {0};
float paycheck;
cout << "WELCOME TO THE EMPLOYEE SALARY GENERATION PROGRAM" << endl << endl;
while (x!="-1") {
cout << "Enter employee name or -1 to stop the program" << endl;
getline(cin, name);
if (name == "-1") return 0;
cout<<"Enter employee code (1=manager, 2=worker, 3=comission, 4=pieceworker) or -1 to stop the program\n";
getline(cin, x);
if (x == "-1") return 0;
if (x.length() == 1)
number = x[0];
else {
cout << "Invalid Input" << endl;
continue;
}
switch (number) {
case '1':
cout << "Your weekly total paycheck is 2 500 $" << endl; // FIXED weekly manager's salary
break;
case '2': // 8.50 per hour + over time for workers
cout << "Please enter the amount of hours worked" << endl;
paycheck = foo();
if(paycheck<40)
paycheck=paycheck*8.50;
else
paycheck= (paycheck-40)*8.50 +(40*8.50);
cout << name << "'s paycheck is " << paycheck << "$" << endl;
break;
case '3': // comission workers make 250 + 5.7% of their weekly sales
cout << "Please enter amount of weekly sale made" << endl;
paycheck = foo();
paycheck = paycheck*5.7/100 + 250;
break;
case '4': // pieceworkers make 50$ per item produced
cout<<"Please enter the number of items produced this week" << endl;
paycheck = foo();
paycheck = paycheck*50;
cout<<"The employee " << name << " Made "<< paycheck << "$ this week" << endl;
break;
default:
cout << "Invalid Option." << endl;
break;
}
}
system ("PAUSE");
}

The main lesson to take away from this is: always check after reading that the read was successful! It wasn't don't proceed. In general, input looks something like this:
if (in >> var1 >> var2) { ... }
if (std::getline(in, string)) { ... }
... you'd use the input in the condition of a loop. Your main problems seem that the input for strings using in >> s first skips leading spaces and then reads non-space characters up to the first space (where space actually is any whitespace like space, newline, carriage return, form feed, backspace, etc.). If you want to read multiple words you'd need to determine how to best tell that reading should stop. For example you could read up to a specific character using std::getline(in, s, c) (where c defaults to \n if omitted).
If you try to read a value which can't be parsed successfully, e.g. when trying to read a number when the next non-space character isn't a digit, the stream will go into fail stated (i.e. its state gets the std::ios_base::failbit set) and it won't do anything useful until the state is clear()ed.

Use std::string
std::string myName;
std::getline(std::cin, myName);

Related

Code skips next cin after leaving function

I am working on a little text based adventure game, the first project I've ever worked on for my own enjoyment, and have ran into a problem. I have got it to ask if you want to play, what your name will be and then the problem starts when you try to choose a race. It works just fine when the user types the first character but when they type the string it will skip past the gender, and class cin. Do I have to clear the cin? Or is my code just wrong?? Thanks for any help you can provide.
#include "pch.h"
#include <iostream>
#include <string>
#include <cctype>
#include <map>
using namespace std;
enum races { Human, Orc, Elf, Dwarf};
enum classes { Warrior, Mage, Archer, Assassin};
const std::map< char, string > race_map =
{ {'H', "human"}, {'O', "orc"}, {'E', "elf"}, {'D', "dwarf"} };
const std::map< char, string > class_map =
{ {'W', "warrior"}, {'M', "mage"}, {'Ar', "archer"}, {'A', "assassin"}
};
void gameIntro();
void gameStart();
void raceFunc(char race);
void playerClassFunc(char playerClass);
void gameIntro()
{
string playerName;
char race;
char sex;
char playerClass;
cout << "Enter your name: \n";
cin >> playerName;
cout << "\n";
cout << "Select a race (Human, Orc, Elf, Dwarf): \n";
cin >> race;
cout << "\n";
raceFunc(race);
cout << "Select Gender (M or F): \n";
cin >> sex;
cout << "\n";
cout << "Select a class (Warrior, Mage, Archer, Assassin): \n";
cin >> playerClass;
cout << "\n";
playerClassFunc(playerClass);
gameStart();
}
void raceFunc(char race)
{
race = toupper(race);
switch (race)
{
case 'H':
cout << "You chose Human!\n\n";
break;
case 'O':
cout << "You chose Orc!\n\n";
break;
case 'E':
cout << "You chose Elf!\n\n";
break;
case 'D':
cout << "You chose Dwarf!\n\n";
break;
default:
cout << "Please choose from the following. Program closing.\n";
system("pause");
exit(0);
}
}
void playerClassFunc(char playerClass)
{
playerClass = toupper(playerClass);
switch (playerClass)
{
case 'W':
cout << "You chose Warrior!\n";
break;
case 'M':
cout << "You chose Mage!\n";
break;
case 'Ar':
cout << "You chose Archer!\n";
break;
case 'A':
cout << "You chose Assassin!\n";
break;
default:
cout << "Please choose from the following. Program closing.\n";
system("pause");
exit(0);
}
}
void gameStart()
{
}
int main()
{
char answer;
cout << "Welcome to Dark Horse\n\n";
cout << "This is my fisrt ever actual program I made out of my own free
will lol.\n";
cout << "It is a Text-Based Adventure game. In this game you will make a
character,\n";
cout << "and explore the land of Spelet, battling enemies, leveling up,
getting loot,\n";
cout << "and learning skills! You do not need to capitalize anything but
your character\n";
cout << "name. If a question has (something like this) if you don't
enter whats inside\n";
cout << "the program will CLOSE, so please pay attention! Thank you for
trying it out!\n";
cout << "I really hope y'all enjoy it!\n\n";
do
{
cout << "Would you like to play?\n";
cin >> answer;
if (answer == 'Y')
{
gameIntro();
}
else if (answer == 'N')
{
system("pause");
return 0;
}
else if (answer != 'N' || 'Y' || 'exit')
{
cout << "Come on dog it's Y or N...yes or no...\n\n";
}
} while (answer == 'N' || 'Y');
system("pause");
return 0;
}
"cin, of class istream, is the standard input channel used for user input. This steam corresponds to C's stdin. Normally, this stream is connected to the keyboard by the operating system." (Josuttis, 2012, p. 745)
Josuttis, N. (2016). The C++ Standard Library: A Tutorial and Reference 2nd Edition: Addison-Wesley
The types are important.
char race;
std::cout << "Please enter your race:" << std::endl;
std::cin >> race;
If the user enters "Human", the standard input stream contains Human and the race variable now has the value H (of type char). The standard input stream now contains uman.
char gender;
std::cout << "Please enter your gender:" << std::endl;
std::cin >> gender;
Calling >> with std::cin gets another character from the standard input stream (in this case u) and stores it in gender. The standard input stream now contains man.
While it appears that the gender question was skipped, you can now see that this is not the case. The input stream still contains characters. If you look at your first screenshot you can see that "Mage" was selected. This is because the value of playerClass is m, the same m from when you entered human.
One way to remedy this is to use std::string instead of char to store the input. That way you have more flexibility in parsing what the user enters (e.g. you can allow for H or Human).

Is there a way to input different value for the same data when the same function is called multiple times?

I'm creating a student data management program in C++ and the function to insert examination marks is buggy.
The code given below is enough to recreate the buggy part of the program.
I have tried to increase the size of sub[] to 16
I have tried to insert data one after the other instead of a loop
None of the above seem to solve the problem
Menu function:
char ch;
main_menu:
clrscr();
cout << "Press the key for your choice:\n";
cout << "D -> Edit details\n";
cout << "R -> Get result\n";
cout << "I -> Insert marks\n";
cout << "E -> Exit Program";
choice:
ch = getch();
switch(ch)
{
case 'd':
//edit_nam(); Ignore this one
goto main_menu;
break;
case 'i':
ins_mar();
goto main_menu;
break;
case 'r':
//get_res(); This one is not related to the problem
goto main_menu;
break;
case 'e':
break;
default:
goto choice;
}
Insert marks function:
for(int i = 0; i < 6; i++)
{
clrscr();
cout << "Enter details of subject:" << i + 1;
cout << "\nSubject name:";
cout << "\nMarks:";
gotoxy(14, 1);
cin.getline(student.marks[i].sub, 8);
gotoxy(7,2);
cin >> student.marks[i].mark;
(i != 5) ? cout << "\nPress any key to continue..." : cout << "\nPress any key to return to menu...";
getch();
}
Student structure:
struct stu
{
char name[20];
int ID;
int cls;
mar marks[6];
};
Marks structure:
struct mar
{
char sub[8];
float mark;
}
If the code was working fine, then it would ask the user to enter the marks for all six subjects, every time the function is called in one run.
However, It is not so. In the first time of function call, everything happens in the correct manner, but it does not ask for subject name after first subject in any of the other runs.

How to add char directly after (cin) in c++

I am trying to add a percent sign directly after a users input (so that the user doesn't have to type the percent symbol). When I try this, it either goes to the next line or doesn't work at all.
What I want: _%
// the blank is for the user's input.
Sorry if this is messy, I'm not sure how to add c++ here.
Here are some things that I have attempted:
// used a percent as a variable:
const char percent = '%';
cout << "Enter the tax rate: " << percent; // obviously here the percent
symbol goes before the number.
double taxRate = 0.0;
cin >> taxRate >> percent; // here I tried adding it into the cin after the cin.
cin >> taxRate >> '%'; // here I tried adding the char itself, but yet another failed attempt...
So, is it even possible to do what I am wanting?
It is definitely possible, however iostream does not really provide a proper interface to perform it. Typically achieving greater control over console io requires use of some platform-specific functions. On Windows with VS this could be done with _getch like this:
#include <iostream>
#include <string>
#include <conio.h>
#include <iso646.h>
int main()
{
::std::string accum{};
bool loop{true};
do
{
char const c{static_cast<char>(::_getch())};
switch(c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
// TODO limit accumullated chars count...
accum.push_back(c);
::std::cout << c << "%" "\b" << ::std::flush;
break;
}
case 'q':
{
loop = false;
accum.clear();
break;
}
case '\r': // Enter pressed
{
// TODO convert accumullated chars to number...
::std::cout << "\r" "Number set to " << accum << "%" "\r" "\n" << ::std::flush;
accum.clear();
break;
}
default: // Something else pressed.
{
loop = false;
accum.clear();
::std::cout << "\r" "oops!! " "\r" << ::std::flush;
break;
}
}
}
while(loop);
::std::cout << "done" << ::std::endl;
return(0);
}
I have been having the same prob but I found an alternative, it doesn't automatically put % sign but it can let you add the %sign right after the cin without messing up when you run the code :> this is my homework, hope it helps as an example:
enter image description here
and here's what the output looks like:enter image description here
//Program that computes the total amount of savings after being invested
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
int main()
{
char percent [1];
float IR, IRp, TC, P, I, A;
cout << "Investment Rate:" << setw(10) << left << "";
cin>> IR >> percent;
IRp = IR*.01;
cout << "Times Compounded: " <<setw(10)<<""; //TC
cin>> TC;
cout<<"Principal:" << setw(13) << right << "$"; //P
cin>> P;
A = P*(pow(1 + (IRp/TC), TC));
I=A-P;
cout<<"Interest: " <<setw(15)<<"$ " <<fixed<<setprecision(2)<<I<<endl;
cout<< "Amount in Savings:" <<setw(5)<<"$"<<fixed<<setprecision(2)<<A<<endl;
return 0;

C++ Variables Losing Assignment Inside "if" Loop

So this is a very simple problem I'm sure, but I'm just starting out.
In the program, there is simple input validation. If inputed is entered properly, no issues.
The problem is, when testing the program with an error, like entering a zero or negative number, all the variables are blank (i.e., strings become blank and numbers become zero) in the output.
Thanks ahead of time for the help and insight.
// This menu driven program determines the time sound will take to travel through
// gas, liquid, and solid, given a distance from a user.
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main()
{
// constants
const double AIR_SPEED_RATE_PER_SECOND_SOUND = 1100.0, //in feet per second
WATER_SPEED_RATE_PER_SECOND_SOUND = 4900.0, // in feet per second
STEEL_SPEED_RATE_PER_SECOND_SOUND = 16400.0; // in feet per second
// Program defined variables
double Time_To_Travel = 0.0; // in seconds
string Medium;
// User defined variables
double distance_of_travel; //in feet
int menu_selection;
//Display a menu for mediums of sound conduction.
cout << "Sound travels at different speeds through air, water, and steel." << endl;
cout << "\nThis program will calculate the time it takes, in feet per second, for " \
"sound to travel a given distance." << endl;
cout << "Please select a number choice below:\n\n1. Air\n2. Water\n3. Steel " << endl;
//Get input from user.
cout << "\nEnter Selection: ";
cin >> menu_selection;
cout << "\nEnter distance in feet the sound will travel: ";
cin >> distance_of_travel;
// Input validate selection is on the menu
if (menu_selection >= 1 && menu_selection <= 3)
{
if (distance_of_travel > 0.0) // input validation distance is positive
{
switch (menu_selection) // calculate the time of travel based on user input
{
case 1: Medium = "air";
Time_To_Travel = distance_of_travel / AIR_SPEED_RATE_PER_SECOND_SOUND;
break;
case 2: Medium = "water";
Time_To_Travel = distance_of_travel / WATER_SPEED_RATE_PER_SECOND_SOUND;
break;
case 3: Medium = "steel";
Time_To_Travel = distance_of_travel / STEEL_SPEED_RATE_PER_SECOND_SOUND;
break;
}
}
else
{
cout << "\nPlease enter a distance greater than zero: ";
cin >> distance_of_travel;
}
}
else
{
cout << "\nMenu selection is not 1, 2, or 3.\n\nPlease correctly enter a number 1 through 3: ";
cin >> menu_selection;
}
// Format to four decimal places and display the time sound takes to travel given distance.
cout << fixed << showpoint << setprecision(4);
cout << "Sound would take " << Time_To_Travel << " seconds to travel given distance of " << distance_of_travel << " feet in " << Medium << "." << endl;;
return 0;
}
An if statement is a simple branch, not a loop. At the end of the if, execution continues past the end of the block.
if (menu_selection >= 1 && menu_selection <= 3)
This, when false, will skip the meat of your program and jump to your code that handles invalid input.
else
{
cout << "\nMenu selection is not 1, 2, or 3.\n\nPlease correctly enter a number 1 through 3: ";
cin >> menu_selection;
}
After you input menu_selection again, control flows to
cout << fixed << showpoint << setprecision(4);
cout << "Sound would take " << Time_To_Travel << " seconds to travel given distance of " << distance_of_travel << " feet in " << Medium << "." << endl;;
return 0;
The new input is never acted on, and the untouched values are printed. Replace the initial if with a do {...} while(condition); loop that wraps the user input. Once the input is satisfactory, you can then proceed to the core of the program.
bool is_good;
do
{
is_good = false;
cout << "\nEnter Selection: ";
cin >> menu_selection;
cout << "\nEnter distance in feet the sound will travel: ";
cin >> distance_of_travel;
if (menu_selection < 1 || menu_selection > 3 || distance_of_travel < 0)
cout << "error message here";
else
is_good = true;
} while (!is_good);
You can handle zero, negative number, or all possible inputs that are not defined in your case block by adding default block to your switch statement. Then your code will look like something like this.
switch (menu_selection) // calculate the time of travel based on user input
{
case 1: Medium = "air";
Time_To_Travel = distance_of_travel / AIR_SPEED_RATE_PER_SECOND_SOUND;
break;
case 2: Medium = "water";
Time_To_Travel = distance_of_travel / WATER_SPEED_RATE_PER_SECOND_SOUND;
break;
case 3: Medium = "steel";
Time_To_Travel = distance_of_travel / STEEL_SPEED_RATE_PER_SECOND_SOUND;
break;
default:
// handle zero, negative numbers and so on.
break;
}
Reference: http://www.tutorialspoint.com/cplusplus/cpp_switch_statement.htm

Simple choice function does not seem to work (C++)

I have been working on an exercise in my c++ programming book and it basically is asking me to create a program that will take 3 files, an old master file of client data (account, name, balance), a transaction file (of account names and credits or debits), and then a function to merge this files and output a new master file of client data. I am pretty sure I know how to do this, or even if I don't I think I can figure it out, the problem I am having is with a simple choice selection interface which is implemented exactly the same as another program that works just fine. When I first run the program it will let me input a choice (int) and then run the appropriate function (of which I only have 1 implemented completely, that being the createMasterFile function. After creating entries in the file and having them read back to the screen just for debugging and verification purposees, it will return to the while statement below but if I watch the choice function in both the main function and the enterChoice() function when I make the first selection (the one that works) those variables (according to gdb) do not take on any values until AFTER createMasterFile runs, before that it states that it is not in scope, after it runs through once choice will take on the original value 1 as it hits while, then seems to skip the condition of the while statement, then hits the switch statement which somehow changes choice to 0 which then hits the default case which then returns to the while statement and choice takes on a value of 32767 and again seems to skip the conditional part of the while statement and gets stuck in an infinite loop at this point with choice never changing in value. In a very similar program (the only difference is that the program that works uses binary files instead of sequential files) this works just fine. The interface looks like this:
enum Choices {CREATE_MASTER =1, CREATE_TRANSACTION, SORT_MASTER, UPDATE_MASTER, SORT_TRANS, UPDATE_TRANS, MERGE, END };
int choice;
while ( ( choice = enterChoice()) != END )
{
switch( choice )
{
case CREATE_MASTER:
createMasterFile( inOutOldMasterFile );
break;
case CREATE_TRANSACTION:
break;
case SORT_MASTER:
break;
case UPDATE_MASTER:
break;
case SORT_TRANS:
break;
case UPDATE_TRANS:
break;
case MERGE:
break;
default:
cerr << "Incorrect choice" << endl;
break;
}
}
and the enterchoice() function is:
int enterChoice()
{
cout << "\nEnter your choice below" << endl
<< "1 - Create Master Record" << endl
<< "2 - Create Transaction Record" << endl
<< "3 - Sort Master File In Descending Order" << endl
<< "4 - Update Master File" << endl
<< "5 - Sort Transaction File" << endl
<< "6 - Update Transaction File" << endl
<< "7 - Merge Transaction and Old Master File" << endl
<< "8 - End Program\n?";
int choice;
cin >> choice;
return choice;
}
If you need to see all the code (just for clarity) here it is (for the functions that are currently being used)
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
#include <cstdlib>
using namespace std;
void outputLine( int, const string, double );
void createMasterFile( fstream & );
int numberOfAccounts = 0;
void swap(int * const, int * const);
void swap( string * const, string * const);
void swap( double * const, double * const);
bool descending( int, int);
void sortAccounts(int, fstream &, bool (*)(int, int));
int enterChoice();
int main()
{
// create a fstream object for input and output to be passed to
// the functions that need to manipulate it.
fstream inOutOldMasterFile( "oldmaster.dat", ios::in | ios::out );
fstream inOutTransaction( "trans.dat", ios::in | ios::out );
ofstream outNewMaster( "newmaster.dat", ios::out);
enum Choices {CREATE_MASTER =1, CREATE_TRANSACTION, SORT_MASTER, UPDATE_MASTER, SORT_TRANS, UPDATE_TRANS, MERGE, END };
int choice;
while ( ( choice = enterChoice()) != END )
{
switch( choice )
{
case CREATE_MASTER:
createMasterFile( inOutOldMasterFile );
break;
case CREATE_TRANSACTION:
break;
case SORT_MASTER:
break;
case UPDATE_MASTER:
break;
case SORT_TRANS:
break;
case UPDATE_TRANS:
break;
case MERGE:
break;
default:
cerr << "Incorrect choice" << endl;
break;
}
}
return 0;
}
int enterChoice()
{
cout << "\nEnter your choice below" << endl
<< "1 - Create Master Record" << endl
<< "2 - Create Transaction Record" << endl
<< "3 - Sort Master File In Descending Order" << endl
<< "4 - Update Master File" << endl
<< "5 - Sort Transaction File" << endl
<< "6 - Update Transaction File" << endl
<< "7 - Merge Transaction and Old Master File" << endl
<< "8 - End Program\n?";
int choice;
cin >> choice;
return choice;
}
void createMasterFile( fstream &clientFile )
{
if(!clientFile)
{
clientFile.open("oldmaster.dat", ios::in | ios::out);
}
cout << "Enter the account, name and balance." << endl
<< "Enter end-of-file to end input (^d)\n? ";
int account;
string name;
double balance;
clientFile.seekp( 0, ios::beg );
// read account, name and balance from cin then place in file
while (cin >> account >> name >> balance )
{
numberOfAccounts++;
clientFile << account << ' ' << name << ' ' << balance << endl;
cout << "?";
} //end while
clientFile.seekg( 0, ios::beg );
cout << left << setw(10) << "Account" << setw(13)
<< "Name" << "Balance" << endl << fixed << showpoint;
while( clientFile >> account >> name >> balance)
{
outputLine( account, name, balance );
}
clientFile.close();
}
If this is really obvious I am sorry but I have tried to find some answer for almost 2 days now searching online.
Thanks in advance.
-Bobby
It seems your createMasterFile() reads from std::cin until std::cin goes into failure mode, e.g., because a wrong value was encountered or std::cin reached its end. This function correctly checks the input after reading.
After that, your enterChoice() function is entered without first clearing the failure setting for std::cin and this function doesn't check whether the read is actually successful and it won't because the stream is already in failure mode. The function should probably read the value and return a result something like this:
std::cin >> choice;
return std::cin? choice: ERROR;
Since createMasterFile() clearly leaves std::cin in failure mode, you should probably reset its state before trying to read your choice and probably also ignore the rest of the current line:
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Of course, if there is no further input from std::cin, reading a choice will still fail.