int main () {
const int MAX_INPUT = 99;
string names[MAX_INPUT];
string eraseName;
string newList;
int numNames = 0;
int i = 0;
cout << "How many names do you want (max 99)? ";
cin >> numNames;
do {
if(numNames > MAX_INPUT) {
cout << "Out of memory!" << endl;
break;
}
cout << "Enter name #" << (i+1) << ": ";
cin.ignore();
getline(cin,names[i]);
++i;
}
while (i < numNames);
cout << "What name do you want to eliminate? ";
getline(cin,eraseName);
cout << "Here is the list in reverse order, skipping ";
cout << eraseName << "..." << endl;
i = 0;
for (i = 0; i < numNames; ++i) {
cout << names[i] << endl;
}
return 0;
}
I have an assignment where I have to "eliminate" an element in an array and recreate the output. I know my final for loop will not erase the element, it's just there because I was testing the issue, but if names has two inputs (John Doe and Jane Doe) and I say to cout them the final loop couts:
John Doe
ane Doe
Move cin.ignore() right after cin >> numNames;, before the loop that reads the names.
You only need this to ignore the newline that is left in the stream after reading the number of names. getline() reads (and ignores) the newline from the stream, so there's no need to call ignore() again before reading each name. As a result, it's reading and ignoring the first character of the name.
The following block of code
if(numNames > MAX_INPUT) {
cout << "Out of memory!" << endl;
break;
}
does not need to be executed in every iteration of the do-while loop. You can change you function to use:
if(numNames > MAX_INPUT) {
cout << "Out of memory!" << endl;
// Deal with the problem. Exit??
}
do {
cout << "Enter name #" << (i+1) << ": ";
cin.ignore();
getline(cin,names[i]);
++i;
} while (i < numNames);
Once you move the check out of the loop, you have to ask yourself, "Do I need to ignore a character in each iteration of the loop?" The answer is "No". You need to ignore the newline only after reading numNames. So, you move it out of the loop also.
if(numNames > MAX_INPUT) {
cout << "Out of memory!" << endl;
// Deal with the problem. Exit??
}
// Ignore the newline left on the stream before reading names.
cin.ignore();
do {
cout << "Enter name #" << (i+1) << ": ";
getline(cin,names[i]);
++i;
} while (i < numNames);
You can improve on that by making sure that everything up to and including the newline is ignored by using:
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Add
#include <limits>
to be able to use std::numeric_limits.
Related
After my first entry, my second entery name field fills up with the input buffer from the previous entry. Why? I am even using the getline but the problem still persists. Please help me with the problem. This is question from Jumping Into C++ book .
#include <iostream>
#include <string>
using namespace std;
struct Person
{
string name;
string address;
long long int PhoneNumber;
};
void displayEntries(Person p[])
{
int enteryNumber;
cout << "Enter the entry number of the person for details(enter 0 to display all entries): ";
cin >> enteryNumber;
if(enteryNumber == 0)
{
for(int i = 0; i < 10; i++)
{
cout << "Entery Number: " << i + 1;
cout << "Name: " << p[i].name << endl;
cout << "Address: " << p[i].address << endl;
cout << "Phone Number: " << p[i].PhoneNumber << endl;
}
}
do
{
cout << "Entery Number: " << enteryNumber;
cout << "Name: " << p[enteryNumber].name << endl;
cout << "Address: " << p[enteryNumber].address << endl;
cout << "Phone Number: " << p[enteryNumber].PhoneNumber << endl;
} while (enteryNumber != 0);
}
int main()
{
Person p[10];
for(int i = 0; i < 10; i++)
{
cout << "Enter the details of the person\n\n";
cout << "Name: ";
getline(cin, p[i].name);
cout << "Address: ";
getline(cin, p[i].address);
cout << "Phone Number: ";
cin >> p[i].PhoneNumber;
cout << endl;
}
displayEntries(p);
return 0;
}
You can see what is happening when you read the reference for getline:
When used immediately after whitespace-delimited input, e.g. after
int n;
std::cin >> n;
getline(cin, n); //if used here
getline consumes the endline character left on the input stream by operator>>, and returns immediately. A common solution is to ignore all leftover characters on the line of input with
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
before switching to line-oriented input.
cin >> p[i].PhoneNumber; only gets the number. That leaves the line ending still in the input buffer to be read the next time you try to read a line.
I've seen other questions about this problem but I can't seem to incorporate those in my problem right here.
My Code
cout << "Get User's input\n";
for (int i = 0; i < size; i++)
{
cout << "Enter the author's name: ";
cin.ignore();
getline(cin,a[i].name); // Ariel the Mermaid
cout << endl;
for (int count = 0; count < size; count++)
{
cout << "Enter Title " << count + 1 << " : ";
cin.ignore();
getline(cin,a[i].books[count].title); // Intro to Me
if (a[i].books[count].title == "NONE")
break;
cout << "Enter Price " << count + 1 << " : $";
cin >> a[i].books[count].price; // 49.99
}
cout << endl;
}
When I have inputted "Ariel the Mermaid", it gives me "riel the Mermaid" when I cout it. Also the "Intro to Me" gives "ntro to Me".
What's the problem with this code?
You are skipping the first character with cin.ignore().
A good use of cin.ignore() is when you have cin >> before a getline()
for example:
cout << "Digit you age" << endl;
cin >> age;
cout << "Digit your full Name" << endl;
cin.ignore();
getline(cin,name);
This happens because when the compiler reachs the cin will make a stop to read from the keyboard until you pressed the enter key to finish, then the getline() will capture the last character wich is a "\n". So you have to cin.ignore() to ignore that last character.
Your call to cin.ignore() is ignoring one character. This method ignores a count of n characters provided as an argument. The default n is 1.
You should delete the line with cin.ignore ().
I have to write a program without using strings . Here is my code :
#include <iostream>
#include <iomanip>
using namespace std;
struct product
{
char productName[100];
double productPrice = 0;
};
const int MAX_CHAR = 101;
const int MAX_ITEM = 100;
int main()
{
product item[MAX_ITEM];
double total = 0;
int count = 0;
for (int i = 0; i < MAX_ITEM; i++)
{
cout << "Please , enter the product name(for checkout type -1) : ";
cin.get(item[i].productName, MAX_CHAR, '\n');
cin.ignore(100, '\n');
if (strcmp(item[i].productName, "-1") == 0 ) {
break;
}
else {
count++;
cout << "Please , enter the price for " << item[i].productName << " : $";
cin >> item[i].productPrice;
cin.ignore(100, '\n');
total += item[i].productPrice;
cout << endl << "Product entered : " << item[i].productName << " " << "$"
<< fixed << setprecision(2) <<item[i].productPrice << endl;
cout << "Total : $" << total << endl << endl;
}
}
cout << endl << "###############";
cout << endl << "Your Receipt : " << endl << endl;
for (int i = 0; i < count; i++) {
cout << item[i].productName << " $" << fixed << setprecision(2) << item[i].productPrice << endl;
}
cout << endl << "Total : $" << total;
cout << endl << "###############";
getchar();
getchar();
return 0;
}
I have a couple questions :
Why does the program crash if I don't use cin.ignore(100, '\n'); after cin >> item[i].productPrice; ? It's just cin without any condition, so it should not leave a new line char in input stream?
How can I check if the price doesn't contain incorrect input (so it has only decimal or floating point numbers) ?
How can I check if the name contains chars and numbers which are >0 (except -1) ?
Is it better to use cin.getline in this case ?
cin is an istream, so it should leave the newline char in the stream if you use cin.get(). I haven't tested if this is the cause of your crash but it sounds like this could give you problems.
chars are just numbers. A . is 46, the digit characters are from 48 through 57. You could read your price input into a buffer and check if you read any char that does not have one of your desired values. If you find an unwanted char, you can decide if you want to repeat the input, ignore this item or exit the program.
In your else branch, check if the first character of productName is a '-'. That way, you already ensured that productName is not -1.
cin.getline() discards the newline character, so you could avoid the use of cin.ignore().
I have a personal project I've been working on. To work, it needs to accept a lot of data (relatively) from the user, in the form of four different kinds of data for 12 users. As such, I have quite a lengthy sequence of statements similar to this:
cout << '\n' << "Monster A's name is: ";
cin >> nameA;
cout << '\n' << "Monster A rolled: ";
cin >> rollM_A;
cout << '\n' << "Monster A's Dex is: ";
cin >> DexA;
cout << '\n' << "Monster A's Mod is: ";
cin >> ModA;
cout << '\n' << "Monster A's Level is: ";
cin >> LvlA;
etc.
Occasionally, however, there might only be a need to input data for less than 12 monsters, say, 5-6 or even 1-2. I'd like to be able to use a command to skip the input section to the rest of the code based on something like a keystroke. i.e. If the user has put in data for 5 monsters, and that's all they require, they could hit the backslash to skip the rest of the input sequence.
Does what I'm talking about make any sense/is there an STL command to do what I'm looking for? Currently, this process isn't looped, but would exiting it be easier if it was inside a loop? I did have a thought of trying something like this:
while(cin.get() != '\') {
cout << '\n' << "Monster A's name is: ";
cin >> nameA;
//etc...
}
EDIT: The above attempt builds, but upon entering the desired keystroke, it quickly and endlessly prints the user prompts without accepting data. Any advice? All I want is for it to break and move on. Can I use a switch statement effectively?
Thanks!
That could work. You can also use EOF, which is more general, than '\'. Then when you are done, hit Ctrl-D to send the EOF, and you are done. This takes care of the situation when some player enters '\' as the Monster's name.
I just tested this set of code and it seems to work how you would like. Of course you will have to modify it to fit your original application.
std::string in;
while (true) {
std::cout << "Enter a name\n";
std::cin >> in;
if (in == "#")
break;
std::cout << "\nMonster A's name is: " << in << "\n";
}
In order to incorporate the limit of the number of monsters, rather than having the true parameter passed into the while loop, simply add a counter to how many monsters are created and break on that condition:
int num_monsters = 0;
while (num_monsters <= 12) {
...
num_monsters++;
}
Hope this helps.
You can check if the name is \, it is not user friendly but it works.
string name;
while (name != "\\") {
cout << '\n' << "Monster A's name is: ";
cin >> name;
cout << "Received " << name << '\n';
if (name != "\\") {
// do something with name ...
}
}
If the loop still loops endlessly, refer to How do I flush the cin buffer? and try clearing stdin buffer.
[edit] I fixed an error in the loop
Here's something I wrote.
struct Monster {
string name;
bool roll;
float dex;
float mod;
float level;
Monster(void) :
name(),
roll(false),
dex(0),
mod(0),
level(0) { }
};
bool getMonsterInformationFromStdin(int index, Monster& monster) {
string end_char = "\\";
string name, roll, dex, mod, level;
cout << '\n' << "Monster " << index << "'s name is: ";
cin >> name;
if (name.compare(end_char) == 0) return false;
monster.name = name;
cout << '\n' << "Monster " << index << " rolled: ";
cin >> roll;
if (roll.compare(end_char) == 0) return false;
monster.roll = (roll[0] == 'y' || roll[0] == 'Y') ? true : false;
cout << '\n' << "Monster " << index << "'s Dex is: ";
cin >> dex;
if (dex.compare(end_char) == 0) return false;
monster.dex = atof(dex.c_str());
cout << '\n' << "Monster " << index << "'s Mod is: ";
cin >> mod;
if (mod.compare(end_char) == 0) return false;
monster.mod = atof(mod.c_str());
cout << '\n' << "Monster " << index << "'s Level is: ";
cin >> level;
if (level.compare(end_char) == 0) return false;
monster.level = atof(level.c_str());
return true;
}
int main(int argc, char** argv) {
int max_monsters = 10;
for (int i = 0; i < max_monsters; i++) {
Monster m;
if( !getMonsterInformationFromStdin(i, m) ) break;
string roll = m.roll ? "rolled" : "didn't roll";
cout << m.name << " " << roll << " dex: " << m.dex << " mod: " << m.mod << " level: " << m.level << endl;
}
return 0;
}
I think this is problem can be solved by using a sentinel Monster name, as u can see below.
const string SentinelName = "%^&";
while(true)
{
cout << '\n' << "Monster A's name is(if u want to end, pls input %^&): ";
cin >> nameA;
if(strcmp(nameA, SentinelName.s_str())
break;
cout << '\n' << "Monster A rolled: ";
cin >> rollM_A;
cout << '\n' << "Monster A's Dex is: ";
cin >> DexA;
cout << '\n' << "Monster A's Mod is: ";
cin >> ModA;
cout << '\n' << "Monster A's Level is: ";
cin >> LvlA;
}
Hope this can solve ur problem. Besides, A little advice for ur code, u can encapsulate the attributes of the monster, such as the name, mode level, etc into a class and this will make ur code look fancier.
I am doing a quiz and testing the user. If the user is wrong he is allowed a second chance or skip, if he chooses 2nd chance and is wrong again, the game is over. How do I break out of this loop to end the game? I tried a do while loop,
do { stuff} while (wrong<2) while counting ++wrong;
every time he's wrong, but didnt work.
I have labeled the ++wrong with // statements below
void player_try (string questions[][5], char answers[])
{
char user_guess;
int m = 0;
srand(time(NULL));
int x;
int choice;
int wrong =0;
for (m=0; m<7; m++)
{
do
{
x = (rand() % 7);
cout << user_name << ": Here is question number " << m+1 << endl;
cout << m+1 << ". " << questions[x][0]<< endl;
cout << "A. " << questions[x][1]<< endl;
cout << "B. " << questions[x][2]<< endl;
cout << "C. " << questions[x][3]<< endl;
cout << "D. " << questions[x][4]<< endl;
cin >> user_guess;
user_guess = toupper(user_guess);
while (!(user_guess >= 'A' && user_guess <= 'D'))
{
cout << "Please choose a valid answer.";
cin>> user_guess;
}
if (user_guess != answers[x])
{
cout <<"Wrong!" <<endl;
++wrong; // THIS IS WHERE I COUNT WRONG ONCE
cout << "Skip this question or take a chance at greatness?" << endl;
cout << "Press 1 to skip, press 2 to take a chance at greatness" << endl;
cin >> choice;
if (choice == '1')
{
cout << "we shall skip this question." << endl;
}
else
{
cout << "I applaud your bravery." << endl;
cout << user_name << ": Here is question number " << m+1 << endl;
cout << m+1 << ". " << questions[x][0]<< endl;
cout << "A. " << questions[x][1]<< endl;
cout << "B. " << questions[x][2]<< endl;
cout << "C. " << questions[x][3]<< endl;
cout << "D. " << questions[x][4]<< endl;
cin >> user_guess;
user_guess = toupper(user_guess);
while (!(user_guess >= 'A' && user_guess <= 'D'))
{
cout << "Please choose a valid answer.";
cin>> user_guess;
}
}
if (toupper(user_guess) != answers[x])
{
cout <<"Wrong!" <<endl;
++wrong;; // THIS IS WHERE I CANT WRONG TWICE
}
else
{
cout << "correct!" << endl;
}
}
else
{
cout << "correct!" << endl;
}
}
while(wrong < 2);
}
}
Change your function return type to an integer. That simply means changing "void" to "int."
Then, inside the function place a return 0; at the point you want your function to terminate. Be sure you include another return 1; for the case that the user wins too.
This is how the main() function works. Consider:
int main()
{
string tester = "some string";
if(tester == "some string")
return 1;
cout << "Hey!"
return 0;
}
In the above case, main() terminates at the "return 1;" because the if statement was TRUE. Note that "Hey!" is never printed. It'll work the same way for your function.
As a plus, you can use that return value to let OTHER functions (such as main()) know if the function terminated because the user won (it returned 1), or lost (it returned 0).
Yes, a break statement is also a valid way to terminate the loop, but I submit that this method is the safer, cleaner way to go about it. In general, we like to know whether a function or program was successful or not.
You can use a break; statement if the person has gotten the answer wrong twice.
As per comments. You can shed the do while loop in favour of one for loop. Just put a break at the bottom if the wrong guesses are 2
There are several great suggestions for refactoring the code to remove the duplication of effort here, but to get the program functioning immediately, you've got to break out of the for loop surrounding the do { } while(wrong < 2) loop.
A simple way to do this is to modify the for loop to test the wrong variable also. The added benefit is, if I'm reading everything correctly, you'll no longer need the do{ } while(); loop.
for (m=0; m<7 && wrong < 2; m++)