C++ getline forces to close a console application with space - c++

The explanation:
Working with two input streams streams, both use getline() to capture the user input. The first getline() is called in the userStringPrompt() function:
string userStringPrompt()
{
string userString;
cout << "Enter a string: ";
getline(cin, userString);
return userString;
}
That sets a string that the program will use later to perform functions, like count its consonants, its vowels, etc.
The second input is used in the menu selection (choose what function/method to perform on the above string):
string userMenuPrompt()
{
string userString;
getline(cin, userString);
return userString;
}
This takes in a user input: A, B, C, D, E and performs an action. For example, if a user inputs into the first input stream:
Hello
and then enter "A" in the second input stream, it should count the vowels in hello, then return the number from the calculation, e.g. 2
The issue:
The program functions correctly when the input in userStringPrompt is without spaces. For example, Hello works, but Hello World would break the application and cause a force close. I'm not sure why, since I am capturing the stream with getline(cin, string).
The entire code:
#include <string>
#include <iostream>
using namespace std;
string userStringPrompt();
string userMenuPrompt();
void showMenu();
int countConsonants(string *ptr);
int countVowels(string *ptr);
int countConsonantsVowels(string *ptr);
int main()
{
string userInput = "";
string userString;
bool userStringSet = false;
while (userInput != "e") {
if (!userStringSet) {
userString = userStringPrompt();
userStringSet = true;
}
showMenu();
userInput = userMenuPrompt();
string *pointerVariable = &userString;
if (userInput == "a") {
cout << endl;
cout << "Vowel count in \"" << userString << "\": " << countVowels(pointerVariable) << endl;
cout << endl;
break;
}
if (userInput == "b") {
cout << endl;
cout << "Consonants count in \"" << userString << "\": " << countConsonants(pointerVariable) << endl;
cout << endl;
break;
}
if (userInput == "c") {
cout << endl;
cout << "Vowel count in \"" << userString << "\": " << countVowels(pointerVariable) << endl;
cout << "Consonants count in \"" << userString << "\": " << countConsonants(pointerVariable) << endl;
cout << endl;
break;
}
if (userInput == "d") {
userStringSet = false;
break;
}
}
return 0;
}
int countConsonants(string *ptr) {
string getVar = *ptr;
int stringSize = getVar.length();
int vowelCount = countVowels(ptr);
int totalConsonants = stringSize - vowelCount;
return totalConsonants;
}
int countVowels(string *ptr) {
int vowelsToCount = 0;
string stringVar = *ptr;
for (int i = 0; i < stringVar.length(); i++){
if (tolower(stringVar[i]) == 'a' || tolower(stringVar[i]) == 'e' || tolower(stringVar[i]) == 'i' || tolower(stringVar[i]) == 'o' || tolower(stringVar[i]) == 'u') {
vowelsToCount++;
}
}
return vowelsToCount;
}
int countConsonantsVowels(string *ptr) {
int count = countConsonants(ptr);
count += countVowels(ptr);
return count;
}
string userStringPrompt()
{
string userString;
cout << "Enter a string: ";
getline(cin, userString);
return userString;
}
string userMenuPrompt()
{
string userString;
getline(cin, userString);
return userString;
}
void showMenu() {
cout << "A) Count the number of vowels in the stream" << endl;
cout << "B) Count the number of consonants in the stream" << endl;
cout << "C) Count both the vowels and consonants in the stream" << endl;
cout << "D) Enter another string" << endl;
cout << "E) Exit the program" << endl;
}
Any guidance/hints would be greatly appreciated. I'm absolutely confused.

I guess your program is not crushing, it's just normally exits.
The program '[8776] Chapter10.exe' has exited with code 0 (0x0).
which is ok, no error code returned.
When you run your program it asks for input, do its work and because there is no more work for it - exits. To see the output you can do one of the following:
Try to run it with Ctrl + F5 in VS, it will add pause command to the end.
Another way to run it is to open command line and run it from there.
Also in your case I guess the problem is in break statements. When you choose what to do with the string you break your loop (which should run while user enters e). Remove all breaks and it will be fine.

Related

How do I validate a string to make sure there is no non-digits and integers less than or equal to 1?

So I am currently working on a program in c++. I have written the following function. The line where it says "//code here" is where my issue is. Basically the program allows the user to create their own quiz txt file. For the question "How many questions should the quiz have?" the user will enter a number that represents the amount of questions. The issue arises when the user input will have to be validated.
Can anyone help me create a loop that does the following?
makes sure the user enters only numbers.
makes sure the numbers entered are greater than 1.
gives the user an error message if they entered a non digit.
gives the user an error message if they entered a number less than 2.
the program validates if the user just presses the enter key.
Once that is all sorted out the program will set NumberOfQuestions equal to the user input after converting it to an int.
void WriteOutQuestions(string &QuizName)
{
ofstream WriteOut;
string filename = "";
string userInput = "";
int numberOfQuestions;
char userInputChar = '0';
bool IncludeCommments = false;
cout << "Name your file\n";
getline(cin, filename);
cout << "Now give your new quiz a title\n";
getline(cin, QuizName);
cout << "How many questions should the quiz have?\n";
getline(cin, userInput);
//code here
numberOfQuestions = stoi(userInput);
cout << "The quiz will contain " << numberOfQuestions << " questions." << endl;
cout<< "Would you like to include comments in any of the choices?\n";
cout << "[Y/y for yes N/n for No]\n";
getline(cin, userInput);
if (userInput == "y" && userInput == "Y")
IncludeCommments = true;
else
cout << "Comments disabled by user...\n";
WriteOut.open(filename + ".txt");
if (!WriteOut)
{
cout << "The file was not found...\n";
}
else
{
cout << "File was read!\n";
}
WriteOut << QuizName << endl;
WriteOut << numberOfQuestions << endl;
for (int i = 0; i < numberOfQuestions; ++i)
{
cout << "What is question number " << i + 1 << "?\n";
getline(cin, userInput);
WriteOut << "Q" << i + 1 << " " + userInput << endl;
cout << "What is choice A for question number " << i + 1 << "?\n";
getline(cin, userInput);
WriteOut << "A) " + userInput << endl;
if (IncludeCommments == true)
{
cout << "What is the comment for choice A for question number " << i + 1 << "?\n";
getline(cin, userInput);
WriteOut << userInput << endl;
}
else
WriteOut << "" << endl;
cout << "What is choice B for question number " << i + 1 << "?\n";
getline(cin, userInput);
WriteOut << "B) " + userInput << endl;
if (IncludeCommments == true)
{
cout << "What is the comment for choice B for question number " << i + 1 << "?\n";
getline(cin, userInput);
WriteOut << userInput << endl;
}
else
WriteOut << "" << endl;
cout << "What is choice C for question number " << i + 1 << "?\n";
getline(cin, userInput);
WriteOut << "C) " + userInput << endl;
if (IncludeCommments == true)
{
cout << "What is the comment for choice C for question number " << i + 1 << "?\n";
getline(cin, userInput);
WriteOut << userInput << endl;
}
else
WriteOut << "" << endl;
cout << "What is choice D for question number " << i + 1 << "?\n";
getline(cin, userInput);
WriteOut << "D) " + userInput << endl;
if (IncludeCommments == true)
{
cout << "What is the comment for choice D for question number " << i + 1 << "?\n";
getline(cin, userInput);
WriteOut << userInput << endl;
}
else
WriteOut << "" << endl;
cout << "Which choice is the right one? [A, B, C or D]\n";
getline(cin, userInput);
while (userInput != "a" && userInput != "A" && userInput != "b" && userInput != "B" &&
userInput != "c" && userInput != "C" && userInput != "d" && userInput != "D")
{
cout << "Only A-D is accepted\n";
}
userInputChar = userInput[0];
if (userInputChar > 96)
{
userInputChar -= 32;
}
userInput = userInputChar;
cout << "userinput contains " << userInput << endl;
cout << "userinputchar contains " <<userInputChar << endl;
WriteOut << userInput << endl;
}
WriteOut.close();
}
first of all you need to change the && in the below code to || to run the code the code correctly
if (userInput == "y" && userInput == "Y")
IncludeCommments = true;
else
cout << "Comments disabled by user...\n";
and coming to the validation you can maintain a flag variable after taking userinput
cout << "How many questions should the quiz have?\n";
getline(cin, userInput);
int length=userInput.length(); //gives the length of string entered
int flag=0; //flag variable
for(int i=0;i<length;i++)
{
if((!(userinput[i]>='0'&&userinput[i]<=9))||isspace(s[i])) //i am
considering space is not a problem
{
flag=1;
}
}
if(flag!=0)
{
cout<<"error:Non digit is entered"<<endl
}else
{
int numberofquestions = stoi(userinput);
if(numberofquestions<=1){
cout<<"error:number less than 2 is entered"<<endl;
}
}
There are so many options that it is difficult to make a good recommendation.
I will show you several solutions. The first part has always the same approach:
We run a do loop
First we instruct the user, what to do
Then we read the input
Then we, check, if all are digits
If we have all digits, then we convert to a number
and check, if the number is greater than 1
If we find an error, we loop again. Let`s look at the options in the code below
Index based for loop and compare with character digits
Index based for loop and use of isdigit function
Range based for loop and use of isdigit function
all_of algorithm and use of isdigit function
regex. Will also handle empty lines
Extened regex. Will also handle empty lines AND will check if number > 1
Options 1-4 need an additional check for an empty line. User presses just enter.
Please see code with all options:
#include <iostream>
#include <string>
#include <cctype>
#include <algorithm>
#include <regex>
int main() {
// We try to get input from the user and run a loop as long as it is not OK
bool inputIsOK{};
// This is the number of questions that we want to read
int numberOfQuestions{};
// Ask for valid input from user
do {
// Assume valid input
inputIsOK = true;
// Instruct user
std::cout << "\nHow many questions should the quiz have? Enter a number > 1.\n";
// Read complete line from the user
std::string line{};
if (std::getline(std::cin, line)) {
// Check, if all characters are valid (digits)
// Option 1 -------------------------------------------------------------------
// Index based for loop and compare with character digits
for (size_t i{}; i < line.length(); ++i) {
if (line[i] < '0' || line[i] > '9') {
inputIsOK = false;
std::cerr << "\nError 1: Please enter digits only\n";
break;
}
}
// Option 2 -------------------------------------------------------------------
// Index based for loop and use of isdigit function
for (size_t i{}; i < line.length(); ++i) {
if (not std::isdigit(line[i])) {
inputIsOK = false;
std::cerr << "\nError 2: Please enter digits only\n";
break;
}
}
// Option 3 -------------------------------------------------------------------
// Range based for loop and use of isdigit function
for (const char c : line) {
if (not std::isdigit(c)) {
inputIsOK = false;
std::cerr << "\nError 3: Please enter digits only\n";
break;
}
}
// Option 4 -------------------------------------------------------------------
// all_of algorithm and use of isdigit function
if (not std::all_of(line.begin(), line.end(), isdigit)) {
inputIsOK = false;
std::cerr << "\nError 4: Please enter digits only\n";
}
// Option 1-4 -----------------------------------------------------------------
// For option 1 to 4 you need to additionally check for empty line
if (inputIsOK && line.length() == 0) {
inputIsOK = false;
std::cerr << "\nError 5: Please enter digits only\n";
}
// Option 5 -------------------------------------------------------------------
// regex. Will also handle empty lines
if (not std::regex_match(line, std::regex("\\d{1,6}"))) {
inputIsOK = false;
std::cerr << "\nError 6: Please enter digits only (max 6)\n";
}
// Option 6 -------------------------------------------------------------------
// Extened regex. Will also handle empty lines AND will check if number > 1
if (not std::regex_match(line, std::regex(R"([2-9]|([1-9][0-9]{1,6}))"))) {
inputIsOK = false;
std::cerr << "\nError 7: Please enter number > 1 (Max 6 digits)\n";
}
// End Option -----------------------------------------------------------------
// Check, if number is > 1
if (inputIsOK) {
numberOfQuestions = std::stoi(line);
if (numberOfQuestions < 2) {
inputIsOK = false;
std::cerr << "\nError 8: Number too small. Enter number > 1\n";
}
}
}
else {
std::cerr << "\nError: General problem with input\n";
inputIsOK = false;
std::cin.clear();
}
} while (not inputIsOK);
return 0;
}
You can choose whatever option you want.
However. I would not use one of the above.
I would use the IOstream facilities and directly read an unsigned integer. If the input is wrong, the state of std::cin will goto fail and indicate the problem.
So, you could use that instead:
#include <iostream>
#include <limits>
int main() {
// We try to get input from the user and run a loop as long as it is not OK
bool inputIsOK{};
// This is the number of questions that we want to read
unsigned int numberOfQuestions{};
// Ask for valid input from user
do {
// Instruct user
std::cout << "\nHow many questions should the quiz have? Enter a number > 1.\n";
// Get input. Directly as number
inputIsOK = (std::cin >> numberOfQuestions) && (numberOfQuestions > 1);
// In case of error. Show message
if (not inputIsOK) {
std::cerr << "\nError 1: Wrong input\n";
std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
} while (not inputIsOK);
return 0;
}
The ignore function will delete all the trash taht maybe still in the input buffer.

How to limit character input "cin" to get just one string

I was writing this code for training, and I'm in a problem where if my user write his name followed by a space and something else, the program will mess up my flow. So it's easier if you try the little program and when it ask for name, put like "Robert Red". The problem occurs just when you put something else after the space, if you input just "Robert" all goes good.
This is the code:
// Description: This is a simple replica of the Japanese game Rock, Paper and
// Scissors.
// Author: Ernesto Campese
// Last Update: 11/04/2018
// Version: 0.0.1
#include "std_lib_facilities.h"
int main() {
string username = "";
char userinput;
int rounds = 0;
int wins = 0;
int draws = 0;
int loses = 0;
int user_secret = 0;
vector<string> options = {"Paper", "Scissors", "Rock"};
cout << "Enter your name: ";
cin >> username;
cout << "Welcome " << username << ", this is the game of Rock, Paper and Scissors.\n";
cout << username << " how many rounds you want to do? ";
cin >> rounds;
if (rounds <= 0) {
cout << "You need to play at least one round!\n";
rounds++;
}
cout << "The game is based on " << rounds << " rounds, you versus the CPU.\n";
cout << "Are you ready? (y/n): ";
cin >> userinput;
if (userinput != 'y') {
cout << "\nThank you.\nProgram Terminated by " << username;
return 0;
}
for(int i = 1; i <= rounds; i++) {
// Title of the rounds
if (i == 1) {
cout << "\nLet's start the first round!\n";
} else {
cout << "Round n. " << i << " begins!\n";
}
// USER makes a move
cout << "Which is your move? (r,p,s): ";
cin >> userinput;
cout << '\n' << username << " says... ";
switch (userinput) {
case 'r':
cout << "Rock\n";
user_secret = 2;
break;
case 'p':
cout << "Paper\n";
user_secret = 0;
break;
case 's':
cout << "Scissors\n";
user_secret = 1;
break;
default:
cout << "something weird...\n";
break;
}
// CPU makes a move
int cpu_secret = rand() % 3;
cout << "CPU says... " << options[cpu_secret] << "!\n";
// The program calculates the result.
if (user_secret == cpu_secret) {
draws++;
cout << username << " and the CPU draws!\n\n";
} else if (user_secret == 0 && cpu_secret == 2) {
wins++;
cout << username << " wins!\n\n";
} else if (user_secret == 1 && cpu_secret == 0) {
wins++;
cout << username << " wins!\n\n";
} else if (user_secret == 2 && cpu_secret == 1) {
wins++;
cout << username << " wins!\n\n";
} else {
loses++;
cout << username << " lose!\n\n";
}
}
cout << "\n\nBattle End!\n";
if (wins > loses) {
cout << username << " won the battle!\n";
} else if (loses > wins) {
cout << username << " lost the battle!\n";
} else {
cout << username << " draws the battle!\n";
}
cout << "Thank you " << username << "!\n";
}
You can try it here: Try me
Thank you!
operator>> stops reading input when it finds a whitespace character.
Use std::getline() to read user input with spaces.
Example using your code:
cout << "Enter your name: ";
getline(cin, username);
If you want the user to be able to type in a name that has spaces in it, use std::getline() instead of operator>>:
getline(cin, username);
Otherwise, if you want the user to enter only 1 word for the name, and you want to ignore anything else the user may enter, use std::cin.ignore():
#include <limits>
...
cin >> username;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
Alternatively, you can use std::getline() to read a line, and then use std::istringstream with operator>> to extract the 1st word of the line:
#include <sstream>
...
string line;
getline(cin, line);
istringstream(line) >> username;

How to inverse string without library functions - C++

I'm having trouble with understanding how to output the inverse of the string then store the inverse value and apply it to a string variable to print the string later on. Some errors I receive depending on the structure of the program include : random characters being printed, just the string input being printed, the programming crashing... The program must be able to process this menu:
At one point I had the inverse working, but when I would add for example if(choice == '2') and create the reverse function it would start acting up again.
This is what I have for now :
int main()
{
string userString = "";
int i = 0;
char choice;
char invChar = char(userString[i]);
userString = invChar;
cout << "Please enter a word, a sentence, or a string of numbers." << endl;
getline(cin, userString);
do
{
cout << "\nUSE THIS MENU TO MAINPULATE YOUR STRING\n"
<< "----------------------------------------" << endl;
cout << "1) Inverse String\n"
<< "2) Reverse String\n"
<< "3) To Uppercase\n"
<< "4) Count Number Words\n"
<< "5) Count Consonants\n"
<< "6) Enter a Different String\n"
<< "7) Print the String\n"
<< "Q) Quit" << endl;
cin >> choice;
cin.ignore();
if (choice == '1')
{
for (int i = 0; i <= userString.length(); ++i)
{
if (isupper(userString[i]))
{
char(tolower(userString[i])); // if uppercase - converts to lower - if upper keeps value
invChar += userString[i];
}
userString = invChar;
}
cout << userString;
}
} while (choice != 'q' || choice != 'Q');
Thanks in advance for any tips and tricks!
Did you maybe mean to do this:
for (int i = 0; i < userString.length(); ++i)
{
if (isupper(userString[i]))
{
userString[i] = (tolower(userString[i]));
}
else if(islower(userString[i]))
{
userString[i] = (toupper(userString[i]));
}
}
This will actually inverse. What you were doing before doesn't work, and also only converts to uppercase

C++ : How to assign the same input to a string and an integer in 2 lines?

I'm a very beginner in C++ and I'm actually following the Google tutorial.
Trying to go a little further with the second example, here is my problematic : checking if the input is a number and, if not, being able to restate it in the error message.
Here is a way I used to solve that but the code length tells me that there is a shorter way :
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <stdlib.h>
using namespace std;
bool IsInteger(string str) {
size_t non_num_position = str.find_first_not_of("0123456789-");
size_t sign_position = str.find_first_of("-", 1);
if (non_num_position == string::npos && sign_position == string::npos) {
return true;
}
return false;
}
void Guess() {
int input_number = 0;
string input_string;
do {
cout << "Try to guess the number between 0 and 100 (type -1 to quit) : ";
cin >> input_string;
if (!IsInteger(input_string)) {
int input_string_length = input_string.size();
cout << "Sorry but « " << input_string << " » is not a number." << endl;
cin.clear();
cin.ignore(input_string_length, '\n');
continue;
}
input_number = atoi(input_string.c_str());
if (input_number != -1) {
cout << "You chose " << input_number << endl;
}
} while (input_number != -1);
cout << "The End." << endl;
}
int main() {
Guess();
return 0;
}
Here is the shorter way I try to follow but cin seems to be "emptied" once assigned to input_number (because of the bitwise operator ?) :
void Guess() {
int input_number = 0;
string input_string;
do {
cout << "Try to guess the number between 0 and 100 (type -1 to quit) : ";
if (!(cin >> input_number)) {
getline(cin, input_string);
cout << "Sorry but " << input_string << " is not a number." << endl;
cin.clear();
cin.ignore(100, '\n');
continue;
}
if (input_number != -1) {
cout << "You chose " << input_number << endl;
}
} while (input_number != -1);
cout << "The End." << endl;
}
SOLUTION :
#include <iomanip>
#include <iostream>
#include <string>
using namespace std;
void Guess() {
int input_number = 0;
string input_string;
do {
cout << "Try to guess the number between 0 and 100 (type -1 to quit) : ";
cin >> input_string;
try {
input_number = stoi(input_string);
if (input_number != -1) {
cout << "You chose " << input_number << endl;
}
}
catch (const exception&) {
cout << "Sorry but " << input_string << " is not a number." << endl;
}
} while (input_number != -1);
cout << "The End." << endl;
}
int main() {
Guess();
return 0;
}
The problem with your first attempt is that IsInteger is unnecessarily complicated and long. Otherwise, you had the right idea. Your second attempt is much less correct.... once you read from cin, the data is gone. So, as in the first attempt, you need to store the data in a string.
Here's an example which is a little shorter and doesn't need IsInteger at all:
size_t p = 0;
int input_number = std::stoi(input_string, &p);
if (p < input_string.length())
{
cout << "Sorry but " << input_string << " is not a number." << endl;
conitnue;
}
stoi's second argument tells you where the conversion to integer stopped working. So if there was non-int data in the string (such as '123abc') then p will be somewhere before the end of the string. If p is at the end, then the whole string must have been a number.

Get blank line after calling Palindrome function

So I have these two functions at the top of my program:
string deletespaces(string sentence){
sentence.erase(std::remove(sentence.begin(), sentence.end(), ' '), sentence.end());
return sentence;
}
and
string checkpalindrome(string sentence){
deletespaces(sentence);
if (sentence == string(sentence.rbegin(), sentence.rend())){
cout << sentence << " is a palindrome." << endl;
}
if(sentence != string(sentence.rbegin(), sentence.rend())){
cout << sentence << " isn't a palindrome." << endl;
}
}
This is my main body of code.
int main(){
int x = 1;
string originalsentence;
while (x == 1) {
int a = 1;
int input;
string sentence;
cout << "Press 1 to reverse a string, 2 to check a palindrome, and anything else to quit: ";
cin >> input;
if(input == 1) {
cout << "Enter a sentence to reverse: ";
cin.ignore();
getline(cin,originalsentence);
originalsentence = sentence;
cout << string(sentence.rbegin(), sentence.rend()) << endl;
}
if(input == 2) {
cout << "Enter a sentence to check: ";
cin.ignore();
getline(cin,originalsentence);
originalsentence = sentence;
checkpalindrome(sentence);
}
cout << "Hit 1 if you want to continue, anything else to quit: ";
cin >> x;
}
}
So here is my problem. I am able to put in my choice about whether to reverse a string or check whether the string is a palindrome. However, when I try to reverse the string, it simply gives a blank line, then asks whether I want to continue. When I ask to check a palindrome, it simply says "is a palindrome" regardless of what I input. Any ideas?