I am writing a library program that displays a menu of options letting the user add new books to the library, but in my add statement it accepts the title and then gets caught in an infinite loop. I wrote a book class that mainly uses pointers to assign things, if I need to post that I will. But when you run the program it compiles, displays the menu, and when you choose add a book it accepts the title but as soon as you hit enter it starts an a infinite loop.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
using namespace std;
int main()
{
int bookCounter = 0;
Book library[25];
int menuOption = 0;
char tempt[50] = "\0";
char tempauth[50] = "\0";
char search[50] = "\0";
unsigned int tempp = 0;
do
{
menuOption = 0;
cout << endl << "1. Show the Library" << endl;
cout << "2. Add a Book" << endl;
cout << "3. Search the Library by Title" << endl;
cout << "4. Exit Library" << endl;
cout << "Select a menu option (e.g. 1, 2, etc.): ";
cin >> menuOption;
if(menuOption == 1)
{
for(int i = 0; i < bookCounter; i++)
{
library[i].displayBook();
}
}
else if(menuOption == 2)
{
cout << "Enter the Title: ";
cin >> tempt[50];
cout << endl << "Enter the Author's name: " ;
cin >> tempauth[50];
cout << endl << "How many pages does the book have? (just enter a number, e.g. 675, 300): ";
cin >> tempp;
library[bookCounter].setAuthor(tempauth);
library[bookCounter].setTitle(tempt);
library[bookCounter].setPages(tempp);
bookCounter++;
menuOption = 0;
}
else if(menuOption == 3)
{
cout << "Enter a title you would like search for (will return partial matches): ";
cin >> search[50];
for (int i = 0; i < bookCounter; i++)
{
int temp = strcmp(search, library[i].getTitle());
if (temp == 1)
{
library[i].displayBook();
}
}
}
}while(menuOption != 4);
system("pause");
return 0;
}
The problem is caused by the way you are trying to read into the arrays:
cin >> tempt[50];
This tries to read a single character into the character at index 50 of the array tempt, which is outside the bounds of the array (which has valid indices in the range [0,49]).
This means only the first character of the entered title will be consumed from the output. Similarly for author. Hence, only the first two characters which you have entered are actually read. Then, this line will be encountered:
cin >> menuOption;
Here, what is left in the buffer (the remainder of the title) will be read, expecting a number. As this does not match a valid format for a number, you will get an error flag in cin. This will mean that all resulting inputs will also fail, menuOption will never change and your program gets stuck in a loop.
A solution to your problem would be to read into tempt without index. You can also check if a read has failed using if(cin.fail()) which should only trigger if there's been an error. If so, handle it and then call cin.clear() to reset the error flags.
I think that this line cause the problem,
cin >> search[50];
You're accessing out bound of search array.
One error is when you type in the menu option, the 'return' stays in the input buffer. The next read of char[] in your tempt variable, will be skipped.
Type cin.ignore(); after cin >> menuOption;
Also, you should read tempt instead instead of tempt[50].
This
cin >> tempt[50];
accesses a non-existent entry in the array. You probably meant to code
cin >> tempt;
Or, better, use std::string instead of raw char array.
Related
Jeopardy point adding code.
The program is supposed to get the number of players with a dynamic array.
From there, you can enter players names and it will insert the names into a two-dimensional array.
Then you can choose to call on a player to start adding points to.
After looping a certain amount of times and pressing 0, the while loop will cease to run and will skip down to the for loop outputting players name and then points.
Problem: If I input "1" for playerNumber, and I start adding points to index [0][1] and outputs numbers quite different from the original numbers I put in. If there are more than 2 players, 2 of the 3 players have random numbers while one remains an accurate point count.
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
//GLOBAL SCOPE, all loops and other boxes can use these
//Declaration variables w cout & cin.
int playerNumber;
string playerNames;
bool flag = true;
cout << "How many players are there: ";
cin >> playerNumber;
cout << endl;
//Array Declaration.
string playerList[playerNumber][2]; //Dynamic array. changes during program runtime.
int points[playerNumber]; //Dynamic array. Changes during runtime
//GLOBAL SCOPE, all loops and other boxes can use these
//Assigning values to arrays now.
cout << "Enter the players names: " << endl;
//Assigns player name to each row.
for(int i = 0; i < playerNumber; i++){
cin >> playerNames;
playerList[i][0] = playerNames; //Assigns players name to the array
cout << "Player " << i + 1 << ": " << playerList[i][0] << endl;
}
while(flag){
//LOCAL VARIABLES
int choice = 0; //Always reverts back to zero to prevent addition error.
int pointsValue = 0; //Always reverts back to zero to prevent addition error.
//LOCAL VARIALES
cout << "Press 0 to end game, if not, enter player number: " << endl;
cin >> choice;
if(choice == 0){ //Exit out of the while loop
flag = false;
}
else if(cin.fail()){
cout << "Not a number. Try again." << endl;
cin.clear();
cin.ignore(256, '\n');
}
else if(choice < 0 || choice > playerNumber){
cout << "Choice is less than 0 or greater than player count. Try again." << endl;
}
else{
cout << "Enter points: " << endl;
cin >> pointsValue;
cout << endl;
points[choice - 1] += pointsValue; //Assigns points to points array
playerList[choice - 1][1] = (to_string(points[choice - 1])); //Assigns points to playerNumber.
}
}
cout << endl;
cout << "END OF JEOPARDY. HERE ARE THE POINTS!!!" << endl;
cout << endl;
//Current points for each player
//Shows their name and points
for(int i = 0; i < playerNumber; i++){ //Loops so that player name and points are displayed
string playerName = playerList[i][0];
string totalPoints = playerList[i][1];
cout << playerName << " points: " << totalPoints << endl;
}
return 0;
}
Technically, this is illegal:
string playerList[playerNumber][2];
int points[playerNumber];
The size of the array must be known at compile time (not runtime). Though some compilers allow this as an extension to the language, it is not part of the standard language.
Better choice would have been to use std::vector.
Lets assume your compiler allows this:
The next issue is that you don't initialize the values in the array.
int points[playerNumber]; // This is an array of random numbers.
// Sure if you are doing a debug build the
// compiler may be nice and just set all the
// values to zero as speed is not important
// during debugging. But on a release build
// these could be any value.
Also if we want to be technical its actually undefined behavior to read from the array unless you first write a value. Though usally this is not going to cause the program to crash on most architectures and unfortuantely the code just runs like nothing bad is happening.
You can normall initialize the array like this:
int points[10] = {0}; // but your variable size stuff
// will stop working for that.
-------
// so you will have to manually initialize the members
int points[playerNumber];
for(int loop = 0; loop < playerNumber; ++loop) {
points[loop] = 0;
}
Or if you upgrade to vector:
std::vector<int> points(playerNumber,0); // Size and initial value.
// Though you don't need the
// initial value as vector will
// zero init members.
The last issue I will mention is that you are not consistent on checking if the read worked.
cin >> pointsValue;
What do you think happens to pointsValue if the read fails (ie. the user puts in an illegal value). The proper way to check the user input is to put the read inside an if statement.
if ( std::cin >> pointValue) {
// The read worked `pointsValue` has valid user input
}
else {
// The read faild.
// We don't know what the user input should be
}
The other thing to think about is that user input is line based. They add values hit return. So it is a good tactic to exploit that and read user input by the line. Once you have the line parse that and validate input. That way the standard input stream does not go into a bad state.
std::string line;
if (std::get(std::cin, line)) {
// We have a line of user input.
std::stringstream lineStream(std::move(line));
line.clear();
int choice;
if (lineStream >> choice) {
// We have a valid choice from the user.
// or do we. If the user entered `2x` is that valid input?
// because `choice` is 2; but there is still `x` on the
// input stream.
// That's a choice for you as the developer to make.
// if you don't care, then you have valid input. If you do
// care then you need to check there is no bad data on
// the line.
}
else {
// invalid choice
}
}
else {
// The user input stream just ended.
// This could mean the user entered the end-of-stream character
// or if the user had connected some other stream to the
// standard input on the command line and there is no more
// data to read.
}
I would note that this will probably never work for invalid input.
if(choice == 0){ //Exit out of the while loop
flag = false;
}
else if(cin.fail()){
// If you failed to read data from the std::cin
// the the value of `choice` is probably zero
// (if I remember my standard correctly) so the
// first branch of the if tree will be entered
// and you will never enter this branch.
cout << "Not a number. Try again." << endl;
cin.clear();
cin.ignore(256, '\n');
}
I'm learning c++ and reading c++ primer plus, but I don't understand why this code need two "cin >> ch". I know the first cin will read character that was user input.but then I delete first "cin >> ch" and run code ,the program have no error.So the fist cin is necessary? why the second cin needn't user to input?
#include <iostream>
int main()
{
using namespace std;
char ch;
int count = 0;
cout << "Enter characters; enter # to quit:\n";
cin >> ch; //get a character
while (ch != '#')
{
cout << ch;
++count;
cin >> ch; // get the next character
}
cout << endl << count << " characters read\n";
return 0;
}
You can evaluate your input right inside condition of while loop.
#include <iostream>
int main()
{
char ch;
int count = 0;
std::cout << "Enter characters; enter # to quit:\n";
while (std::cin >> ch && ch != '#')
{
std::cout << "entered: " << ch << std::endl;
++count;
}
std::cout << std::endl << count << " characters read" << std::endl;
return 0;
}
When while condition is entered it will wait for you to enter anything first. Once input is received it will check if the input is not #. If input is not # the loop is entered, input printed out, counter increased, and back to waiting for another input. If # is entered, condition becomes false, and loop is aborted.
If you remove the first cin then count will never be incremented. The user can enter # character before entering the loop and the program can never enter it therefore.
The first cin>>ch is obviously used to take input from user but you
have again accepting data in while loop using the same variable name "ch" ,
So when you run the program it will not give u error but accept only first value that you have accept before the while loop not in while loop.
In while loop you can assign new value to variable "ch" but not accept the new value again.
Current code:
const int MAX_CODENAME = 25;
const int MAX_SPOTS = 5;
struct Team {
string TeamName[MAX_CODENAME];
short int totalLeagueGames;
short int leagueWins;
short int leagueLoses;
};
//GLOBAL VARIABLES:
Team league[MAX_SPOTS];
void addTeams(){
int i = 0; //first loop
int j; //second loop
while(i < MAX_SPOTS){
cout << "****** ADD TEAMS ******" << endl;
cout << "Enter the teams name " << endl;
scanf("%s", league[i].TeamName) ;
}
void searchTeam(){
string decider[MAX_CODENAME];
cout << "Please enter the team name you would like the program to retrieve: " << endl;
cin >> decider[MAX_CODENAME];
for(int i = 0; i < MAX_SPOTS; i++){
if(decider == league[i].TeamName){
cout << endl;
cout << league[i].TeamName << endl;
break;
}else{
cout << "Searching...." << endl;
}
}
}
I really dont know why its not working but I have included all the perquisite header files such as and but the program crashes when i enter the data and then attempt to search. I get the circle of death and then program not responding then says Process returned 255 (0xFF) . It does not even out put Searching.... the program practically gives up as soon as I enter that name.
Also if this can be optimized by the use of pointers that would be great.
tl;dr run-time error causing the search to fail as soon as i type in a name. And for the record I have checked to make sure the name I entered is valid.
scanf doesn't know about std::string. Use std::cin >> league[i].TeamName.
scanf("%s", league[i].TeamName) ;
This should be changed to
std::cin >> league[i].TeamName ;
A couple of other things here....
string decider[MAX_CODENAME];
cout << "Please enter the team name you would like the program to retrieve: " << endl;
cin >> decider[MAX_CODENAME];
Every time you input a value, you are telling the computer to hold the inputted value at decider[25] but the computer only reads indexes 0-24.
if(decider == league[i].TeamName){
Which array slot are you comparing the team name to? If its the 25th element than the statement should be
if(decider[24] == league[i].TeamName){
Pointers are better suited if the number of TeamNames are unknown. Based on the limited code presented, I highly recommend you stay within the realm of basic data types. For the purposes of troubleshooting, please post your full code in the future.
Your TeamName member variable:
string TeamName[MAX_CODENAME];
is an array of 25 strings, so in this line:
scanf("%s", league[i].TeamName) ;
you are courrupting the array. You don't really want an array anyways, so change the TeamName declaration to:
string TeamName;
and then when you read the name, you'll need to use iostreams which knows how to populate a string type (scanf only works with c char arrays):
std::cin >> league[i].TeamName
I want to create a program that when a user inputs something that I didn't define, the program prompts him again.
I did it with if statements but it only loops for 1 time and doesn't do it again. I tried loops but whenever the input is false it just breaks the condition and refuses all inputs alike. In c++.
Any help is much appreciated.
#include <iostream>
#include <string>
using namespace std;
void xD(){string x;
do{cout << "Retry\n";
cin >> x;}while(true);}
//declaring a function to make the shop
void shop(){
string x;
float coins = 500;
float bow_cost = 200;
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
cin >> x;
// if u chose bow you get this and get to choose again
if (x == "bow"){
cout << "you bought the bow.\n you now have " <<coins - bow_cost << " coins." << endl; cin >> x;}
/*now the problem that whenever I excute the code and type something other than bow it gives me the cin only once more and then fails even if I type bow in the 2nd attempt*/
//in my desperate 5k attempt, I tried creating a function for it.. no use.
//i want it o keep prompting me for input till i type "bow" and the other block excutes. but it never happens.
else{xD();}
}
int main(){
string name;
string i;
cout << "if you wish to visit the shop type \"shop\"\n";
cin >> i;
if(i == "shop"){shop();}
else{cin >> i;}
return 0;
}
The problem lies on the condition in this loop block
void xD(){
string x;
do{
cout << "Retry\n";
cin >> x;
}while(true);
}
The while(true) condition makes it loops forever regardless of the input. To fix this, you can change the condition:
void xD(){
string x;
do{
cout << "Retry\n";
cin >> x;
}while(x!="bow");
cout << "you bought the bow. and some other messages"<<endl;
}
That should work. However, it is still too complicated for me. This can be simplified into the snippet below:
void shop(){
string x;
float coins = 500;
float bow_cost = 200;
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
cin >> x;
while (x!="bow"){
cout << "Retry\n";
cin>>x;
}
cout << "you bought the bow.\n you now have " <<coins - bow_cost << " coins." << endl; cin >> x;
}
Instead of doing this approach (which is checking the condition only once):
if (x == "bow"){
cout << "you bought the bow.\n you now have " <<coins - bow_cost << "
coins." << endl; cin >> x;
} else{
xD();
}
which is actually a RECURSIVE invocation to the method xD()
you should do a do-while loop,
example:
while (x.compare("bow") != 0)
{
cout << "sorry, wrong input, try again...";
cin >> x;
}
note the use of the compare method instead of the == operator
here more about it in the documentation
You can use return value of cin >> [your input object] here to check status or istream's method fail(). As soon as input stream fails to parse whole or part of streams it fails and stay in state of failure until you clear it. Unparsed input is preserved (so you can try to parse it differently?)m so if you try to >> again to object of same type, you'll get same failure. To ignore N chars of imput, there is method
istream::ignore(streamsize amount, int delim = EOF)
Example:
int getInt()
{
while (1) // Loop until user enters a valid input
{
std::cout << "Enter an int value: ";
long long x; // if we'll use char, cin would assume it is character
// other integral types are fine
std::cin >> x;
// if (! (std::cin >> x))
if (std::cin.fail()) // has a previous extraction failed?
{
// yep, so let's handle the failure, or next >> will try parse same input
std::cout << "Invalid input from user.\n";
std::cin.clear(); // put us back in 'normal' operation mode
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n'); // and remove the bad input
}
// Thechnically you may do only the above part, but then you can't distingusih invalid format from out of range
else if(( x > std::numeric_limits<int>::max()) ||
( x < std::numeric_limits<int>::min()))
{
std::cout << "Invalid value.\n";
}
else // nope, so return our good x
return x;
}
}
For strings parsing is almost always successful but you'll need some mechanism of comparison of string you have and one that is allowed. Try look for use of std::find() and some container that would contain allowed options, e.g. in form of pair<int,string>, and use int index in switch() statement (or use find_if and switch() within the function you give to it).
Consider that if() statement is a one_direction road, it checks the condition and if the condition was satisfied it goes to its bracket and do blah blah blah , if there is any problem with condition compiler passes ifand jump to compile other codes.
Every time that you begin to compile the codes it begins from int main() function. You did the wrong thing in the if and else statements again
Here is the correct code .I did the necessary changes.
#include "stdafx.h"
#include <iostream>
#include <string>
using std::string;
using std::cin;
using std::cout;
#define coins 500 ;
#define bow_cost 200 ;
int shop(string x)
{
//There is no need to allocate extra memory for 500 and 200 while they are constant.``
cout << "welcome to the shop\n";
cout << "Bow(bow)costs 150 coins.\n";
do
{
cout << "Input another :\n";
cin >> x;
if (x == "bow")
{
return (coins - bow_cost); //return to function as integer
}
} while (true);
}
int main()
{
string name, i;
cout << "if you wish to visit the shop type \"shop\"\n";
cin >> i;
if (i == "shop")
{
cout << "Input :\n";
cin >> name;
cout << shop(name) << "you bought the bow.\n you now have " << " coins." << "\n";
}
//argument passed to shop funnction parameters.
system("pause");
return 0;
}
I have a pretty basic ofstream() question. I have an app that matches data that was inputted by a user in a text document. Can i skip lines with ofstream and not modify text already there? If possible, how? Please forgive me my English isn't too great.
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
int count = 0;
int num;
int numcopy;
string clientNames[3000];
string caseNumbers[3000];
int userInp = 1;
string confirm = "2";
cout << "Do you have a file already started (y/n)?"<<endl;
cin >> confirm;
if(confirm == "y")
{
goto input;
}
if(confirm == "n")
{
goto postinput;
}
input:
cout << "What is the number of the query last entered?";
cin >> userInp;
num = userInp;
numcopy = userInp;
postinput:
for(int i = 1; i <3000; i++)
{
userInp ++;
repeat:
cout <<"Enter Client's Name:";
cin >> clientNames[userInp];
cout << " " <<endl;
cout <<"Enter Case Number:";
cin>> caseNumbers[userInp];
cout <<"Client Name "<< i << " "<<clientNames[userInp]<<endl;
cout << "Case Number" << i << " "<<caseNumbers[userInp]<<endl;
cout <<"Is This Correct?"<<endl;
confirm == " ";
cin >> confirm;
if(confirm == "y")
{
cout <<"Confirmed"<<endl;
}
if(confirm == "n")
{
goto repeat;
}
if(confirm == "/end")
{
break;
}
}
ofstream file;
file.open("caseData.txt");
for(int w = 0; w <3000;w++)
{
num++;
file <<
}
}
"skip lines with ofstream and not modify text already there" is not possible.
But you can store all lines of the file in your program first. And while you are processing the file, output the stored line when you want to leave that line unchanged.
This effectively does what you want.
Also, you really should get rid of the gotos in your code. They should be used only in rare cases. And for beginners, I always feel they should not use it until they are very familiar with programming.
I am going to take a guess that you want to do something about the circumstance when the user has inputted the same clientName or same caseNumber multiple times. It is actually not entirely clear from your question that this is what you want to do, but you asked:
I have an app that matches data that was inputted by a user in a text document. Can i skip lines with ofstream and not modify text already there? If possible, how?
However, I did not see any matching logic in your program. You are simply recording up to 2999 entries (since you don't use the 0 entry of your arrays), or wait until the user enters /end as a confirmation message.
If you had actual matching logic, you could detect on input whether the user has typed in the same clientName or same caseNumber, and you can prompt the user for what to do about it (for example, keep the old existing entry, keep newly entered entry). If you had such logic, you would know that you would only be outputting unique lines of data, and so your output loop would be fairly simple.
There were some comments made on your use of goto. Instead of the repeat: label, you could start another loop:
//repeat:
do {
// ...read in input, echo it back, wait for confirmation...
cin >> confirm;
if (confirm == "y") {
cout << "Confirmed" << endl;
break;
}
} while (confirm != "/end");
if (confirm == "/end") {
break;
}
In this code, anything other than a y or /end is treated the same as n.