I'm trying to create a command menu where the user will be able to perform as many commands as he/she wants until pressing "q" which will end the loop. I think I have everything I need to do this except I realized mid-way that my professor asked to use string. When I included string into the program, I began to get error messages saying "could not convert string to bool" wherever there was a while or if statement. What can I do to fix this problem and get my program working. Thanks in advance.
#include <iostream>
#include <string>
using namespace std;
int main()
{
char option;
char number=0;
string s;
string n;
string p;
string q;
char number2;
cout << " Please enter a number: "<< endl;
cin >> number;
do {
cout << " Please enter a command: " << endl;
cout << " s- square the number " << endl;
cout << " n- add the number and (number +1) " << endl;
cout << " p- add the number and (number -1) " << endl;
cout << " q- quit" << endl;
cin >> option;
if (option=s) {
s= number*number;
cout << "Square of this number is : " << s;
}
else if ( option=n){
number2= number+1;
n= number+number2;
cout << "Sum of" << number << "+" << number2 << "is: " << n;
}
else if (option=p) {
number2= number-1;
p= number+number2;
cout << "Sum of" << number << "+" << number2 << "is" << p;
}
else if (option=q)
cout << "Terminating Program";
} while(option);
return 0;
}
you're assigning in the if and else if rather than comparing.
if (option=s) {
should be
if (option=='s') {
note the double =
Also, you need to put single quotes (') around the character choice.
It's a common mistake that even experienced developers make.
These declarations
char number=0;
string s;
string n;
string p;
string q;
char number2;
should all be int
int number=0;
int s;
int n;
int p;
int q;
int number2;
Let me answer as if I were who will evaluate your homework. You have several issues here:
You are asked to use string. Avoid the use of char and string together.
char option; // professor asked to use string: (-1) point
string option; // ok
When you use a single =, like in option="a", you are assigning the value "a" to the variable option. But in the if-else statements you want to compare, so you should use the == comparison operator. Also, you can't compare a char with a string.
if(option = "a") // error: expression must have bool type: (-2) points
if(option == 'a') // error: no operator "==" matches std::string == char; (-2) points
if(option == "a") // ok
You use while(option), but option is declared as a char, not as a bool. Replace this line to while(option!="q") to finish when you enter q.
while(option); // error: expression must have bool type; (-2) points
while(option != "q"); // GOOD!
Also, your program will finish when you scape from the while-statement; so, try to put the "Terminating Program" message after this.
You do not need to declare such many variables (s, n, p, q, number2). Try to use temporary variables inside each scope, for example:
if (option=="s")
{
cout << "Square of this number is : " << number*number << endl;
}
else if ( option=="n")
{
int number2= number+1;
cout << "Sum of " << number << "+" << number2 << " is : " << number+number2 << endl;
}
In the form you write this code, every time you type a new option you will obtain an output like:
Sum of 10+11 is : 21 Please enter a command:
This is ugly to me (-1 point). Try to put a newline (<< endl;) after every cout lines.
Finally, what if I type any other letter not listed in the menu? I would expect a message like Enter a valid option (-1 point).
Related
The idea behind this code in c++ is to calculate the sum of all the entered numbers. When the user enters 0, the program should stop. This part of the code is working as I intended, but I'd like to include a variant which recognizes that a character different than a float number has been entered, ignore it in the calculation and allow the user to continue entering float numbers. At the moment, entering anything else but a float number stops the program.
I know there's a "if (!(cin >> numb))" condition, I've tried parsing it in different places in the code, but I can't figure out how to force the program to ignore these invalid inputs. I would be very grateful for any help.
#include <iostream>
#include <stdlib.h>
using namespace std;
float numb; float sum=0;
int main()
{
cout << "This app calculates the sum of all entered numbers." << endl;
cout << "To stop the program, enter 0." << endl << endl;
cout << "Enter the first number: ";
cin >> numb;
while(true)
{
sum += numb;
if (numb!=0)
{
cout << "Sum equals: " << sum << endl << endl;
cout << "Enter another number: ";
cin >> numb;
}
else
{
cout << "Sum equals: " << sum << endl << endl;
cout << "Entered 0." << endl;
cout << "Press Enter to terminate the app." << endl;
exit(0);
}
}
return 0;
}
You have three options:
trial and error: try to read a float, and in case of error clear the error flag, ignore the bad input and read again. The problem is that you don't know really how many of the input is to be ignored.
read strings: read space delimited strings, try to convert the string using stringstream, and just ignore the full string in case of error. The problem is that if the input starts with a valid float but then contains invalid characters (e.g. 12X4), the invalid part will be ignored (e.g. X4)
control parsing: read space delimited strings, try to convert the string using std::stof(), and check that all characters of the string where successfully read
Here the second approach, with a slightly restructured loop, so that a 0 entry will lead to exiting the loop and not the full program:
string input;
while(cin >> input)
{
stringstream sst(input);
if (sst>>numb) {
sum += numb;
cout << "Sum equals: " << sum << endl << endl;
if (numb==0)
{
cout << "Entered 0." << endl;
break; // exits the while loop
}
cout << "Enter another number: ";
}
else
{
cout << "Ignored entry "<<input<<endl;
}
}
cout << "Press Enter to terminate the app." << endl;
Online demo
If you prefer a more accurate parsing, consider something like:
size_t pos=0;
float xx = stof(input, &pos );
if (pos!=input.size()) {
cout << "error: invalid trailing characters" <<endl;
}
You have to clear the failbit after a failed read. After that, you can read in the invalid stuff into a string (that you just ignore). This function will read in values and add them up until it encounters a 0 or the end of the input stream.
int calc_sum_from_input(std::istream& stream) {
int sum = 0;
// If it couldn't read a value, we just read the thing into here
std::string _ignored;
while(stream) // Checks if the stream has more stuff to read
{
int value;
if(stream >> value)
{
if(value == 0) // Exit if it read the value 0
break;
else
sum += value; // Otherwise update the sum
}
else {
// Clear the failbit
stream.clear();
// Read ignored thing
stream >> _ignored;
}
}
return sum;
}
The logic is basically:
set the initial sum to 0
check if there's stuff to read
if there is, try reading in a value
if successful, check if the value is 0
if it's 0, exit and return the sum
otherwise, add the value to the sum
otherwise, clear the failbit (so that you can read stuff in again) and read the bad value into a string (which gets ignored)
otherwise, return the value
I'm learning C++ and this is my code:
int val1,val2;
char op;
cout << "Please enter a calculation (operand operator operand):";
cin >> val1 >> op >> val2;
if((val1<0||val1>9)||(val2<0||val2>9)) {
cout << "Operand must be between 0 and 10!" << endl;
}
cout << "val1: " << val1 << " val2: " << val2 << endl;
The validation works but I still haven't just one digit in the variable val1 or val2 if I enter for example 34+56.
I want to end up with an error message for a number that has 2 digits or more and I want to have only one digit in the variables val1 and val2.
I tried working with chars, strings and isdigit() but I'm still in the dark here. Thx for the help!!
#include <iostream>
#include <string>
int main(){
int x = 100;
std::cout << std::to_string(x)[0] - '0';
}
okay that's fine. first digit in the number. I have c++11 solution.
while compiling add compiler flag -std=c++11
First, I'd like to suggest getting your input separately because it will greatly reduce the complexity of your code.
The problem you're facing is that all your inputs are treated at once when writing 34+56 and treated 3 times when read separately like in 34 + 56 (because of the space).
Therefore, what you need to do is read the whole line:
std::cout << "Please enter a calculation:";
std::string str;
std::getline (std::cin, str);
Then, you need to locate the sign and split your string there:
// "34+56"
std::size_t index = str.find_first_of("+-/*"); // returns the index 2
std::string operand1 = str.substr(0, index); // "34"
std::string operand2 = str.substr(index + 1); // "56"
Finally, you can output an
Error message for a number that has 2 digits or more and have only one digit in the variables val1 and val2.
// converts string -> int
int val1 = atoi(operand1.c_str());
int val2 = atoi(operand1.c_str());
// check if in range
if( (val1<0||val1>9) || (val2<0||val2>9) ) {
std::cout << "Operand must be between 0 and 10!" << std::endl;
std::cout << "Using first digit of operands..." << std::endl;
//Edit(wrong operation): Use the leftmost character minus character '0'
val1 = operand1[0] - '0';
val2 = operand2[0] - '0';
}
Notes: I did not actually test this. There are many cases where this will fail(i.e there is more than one operation). You could also argue that finding the first valid character and saving it is more efficient, but I find extracting the whole operands into strings cleaner.
Solved it like this:
while(true) {
cout << "Please enter a calculation (operand operator operand):" << endl;
while(true) {
cin >> val1 >> op >> val2;
if((val1<0||val1>9)||(val2<0||val2>9)) {
cout << "Wrong input! Try again." << endl;
break;
}
cout << "val1: " << val1 << " val2: " << val2 << endl;
}
}
Seems like the most obvious solution. Thxalot!!
I'm writing a program that will take an 8 digit number as input by the user and will evaluate it so if any digit that appears more than 3 times will be labelled as "unacceptable"; if all digits appear 3 or fewer times it is labelled as "acceptable".
So these numbers:
41124535, 13134113, 24255411
would all be labelled as acceptable, but these ones
34233332, 31111412, 55551122
would be labelled as unacceptable.
My approach is if... else chains and nests. So far I've managed to make a chain work, but it can only compare the digits when they repeat up to 2 times. Then I have a nest, but it only works if I write the else part every step of the way, instead of just leaving one single else at the end. This is crucial since the else part in the end will take the algorithm to a new if else nest that will evaluate the rest of the 8 digit long number.
The beginning of the program:
cout << "\n\n\t Input 1st digit:";
cin >> A;
cout << "\t Input 2nd digit:";
cin >> B;
cout << "\t Input 3rd digit:";
cin >> C;
cout << "\t Input 4th digit:";
cin >> D;
cout << "\t Input 5th digit:";
cin >> E;
cout << "\t Input 6th digit:";
cin >> F;
cout << "\t Input 7th digit:";
cin >> G;
cout << "\t Input 8th digit:";
cin >> H;
cout << "\n\t The number is: [";
cout << A;
cout << B;
cout << C;
cout << D;
cout << E;
cout << F;
cout << G;
cout << H;
cout << "]";
the if...else chain:
if (A==B)
cout << " Unacceptable!";
else
if (B==C)
cout << " Unacceptable!";
else
if (C==D)
cout << " Unacceptable!";
else
if (D==E)
cout << " Unacceptable!";
else
if (E==F)
cout << " Unacceptable!";
else
if (F==G)
cout << " Unacceptable!";
else
if (G==H)
cout << " Unacceptable!";
else
cout << " Acceptable";
then the nest with several else commands:
if (A==B)
{
if (A==C)
{
if (A==D)
cout << " Unacceptable!";
else
cout << " Acceptable";
}
else
cout << " Acceptable";
}
else
cout << " Acceptable";
so my guess is an if...else chain with if...else nests for each variable, but I can't work it out.
I'm not sure if you are using nested if statements for a specific reason - challenge, etc.? I'll assume you're not.
You can read the digits as one string - you could read as an int, but then you have to extract the digits from that anyways.
std::string input;
std::cin >> input;
/* validate input, make sure that it's 8 digits,
* that they are all digits, etc. - hint: int isdigit(int c)
*/
You can use a std::map to keep a histogram of the digits.
std::map< char, int > digit_histogram;
for (auto ch : input)
digit_histogram[ch]++;
Then the count of any digit dig is available as digit_histogram[dig]. You can loop through the map, or loop from 0-9 and discard any that is > 3.
This works for any number of digits, and it's 5 lines long without error checking. The point of programming is to make the computer do the work for you ;)
Start with some tests. This helps you understand your requirements, and clarifies your interface and how the function will be called. As this isn't a tutorial on unit testing, I'll just write a simple program that checks all the test cases succeed:
#include <cstdlib>
int main()
{
// these should all return true
if (!validate("41124535")) return EXIT_FAILURE;
if (!validate("13134113")) return EXIT_FAILURE;
if (!validate("24255411")) return EXIT_FAILURE;
// these should all return false
if (validate("34233332")) return EXIT_FAILURE;
if (validate("31111412")) return EXIT_FAILURE;
if (validate("55551122")) return EXIT_FAILURE;
return EXIT_SUCCESS;
}
Obviously this won't compile, as you haven't declared validate(). So let's add it, before main():
#include <string>
bool validate(const std::string& s)
{
return true;
}
It now compiles, but of course it fails because it never returns false. Now we can code the solution. We can count the occurrences of each character with a std::map:
#include <map>
#include <string>
static const int max_repeats = 3;
bool validate(const std::string& s)
{
std::map<char,int> counts;
for (char c: s)
if (++counts[c] > max_repeats)
return false;
return true;
}
Now, this runs, but it fails on the second test (found by commenting out this test and observing a pass - a real unit-test framework would identify the failing test for you).
The failing test has four 1s in it, so it fails. Why was it suppose to succeed? Ah, perhaps we've misinterpreted the requirement! Perhaps it's intended that the string have no more than three consecutive identical characters? Well we can do that too, by keeping count of the most recently seen character and how many repeats.
#include <string>
static const int max_repeats = 3;
bool validate(const std::string& s)
{
char last_seen = 0;
int repeats = 0;
for (char c: s) {
if (c != last_seen) {
// reset the matcher
last_seen = c;
repeats = 1;
} else {
// have we seen too many?
if (++repeats > max_repeats)
return false;
}
}
return true;
}
There are a few things to clean up, such as test cases with exactly three consecutive identical characters, and (perhaps) you might want to validate the length of the argument string.
And you can then convert it into a full program:
#include <iostream>
int main(int argc, char **argv)
{
while (*++argv)
std::cout << *argv << (validate(*argv) ? " OK" : " FAIL") << std::endl;
}
I just started learning files and I understand how to set it up and get it to work. I have to write this program where I have to allow the user to enter some information and have the user also update and adjust any data, using binary.
So I can write up until the point where the user can write to and read from the file. But I don't know how to let the user adjust data or add data.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class client {
public:
string name;
int balance;
string id;
};
int main()
{
int ans;
int x;
string nameIn;
string adjName;
client client1;
ofstream out("client1.dat", ios::binary);
cout << "\nDo you want to add information or update info" << endl;
cin >> ans;
if (ans == 1)
{
cout << "\nPlease enter the name of your client" << endl;
cin >> nameIn;
x = nameIn.length();
if (x <= 10)
{
for (int i; i < 10; i++)
{
adjName[i] = nameIn[i];
}
}
else
{
for (int i = x; i < 10; i++)
{
adjName[i] = ' ';
}
}
client1.name = adjName;
cout << "\nPlease enter the balance of your client" << endl;
cin >> client1.balance;
cout << "\nPlease enter the id of your client" << endl;
cin >> client1.id;
cout << "\nThe name of your client is " << endl << client1.name
<< endl << "\nThe balance of your client is " << endl
<< client1.balance << endl << "\nThe id of your client is "
<< endl << client1.id;
out.write(reinterpret_cast<const char*> (&client1), sizeof(client));
}
/*
else if (ans == 2)
{
string answer, newName,line;
cout << "\nWhat name do you want to update? " << endl;
cin >> answer;
cout << "\nWhat is the new name?" << endl;
cin >> newName;
if (out)
}
*/
system("pause");
return 0;
}
so the name needs to be only 10 characters long, so that we can adjust/update it. It compiles and runs, but every time the compiler gets to the part where it checks the name length, it freaks out and says "debug assertion failed"
string subscript out of range.
Also a thing about this code-- if i run it without the bits where you adjust the name to a certain array length, the program runs, and stores everything nicely. But when I try to read back the .dat, it reads it back but exits with an access violation, forcing me to manually stop the debugging. What am I doing wrong?
this is the code for reading the file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class client {
public:
string name;
int balance;
string id;
};
int main()
{
client client1;
char ans;
cout << "\nDo you want to view the information about your client?"
<< endl;
cin >> ans;
ifstream in("client1.dat", ios::binary);
if (ans == 'y' || ans == 'Y')
{
in.read(reinterpret_cast<char*> (&client1), sizeof(client));
cout << "The name is " << endl << client1.name << endl
<< "The balance is " << endl << client1.balance << endl
<< "The id is " << endl << client1.id << endl;
}
system("pause");
return 0;
}
As for the 1st part:
for (int i; i < 10; i++)
// ^
misses to initialize i to zero. Also what if the input was smaller than 10 characters? You're going to access the std::string out of bounds. You should replace the if/else and loops with simply
adjName = nameIn;
while(adjName.length() <= 10) {
adjName += ' ';
}
to get rid of the debug assertion.
For the 2nd part of the question, as already mentioned in the comments you cannot do this with a structure containing classes like std::string.
The reinterpret_cast<char*> (&client1) just obfuscates that std::string uses a pointer to the dynamically allocated character data internally, and that cannot be restored meaningfully when reading the stored data back later (hence the access violation you get).
A viable way might be to use something like
struct client {
char name[11];
int balance;
char id[5];
};
As I guess you need to do this for a homework exercise, and for this purpose that would probably be sufficient.
But you quickly can see the drawbacks, that the character data needs to be fixed in size and you cannot have arbitrary length strings. I never would use such for production ready code.
Another pitfall (as also mentioned) is, that int isn't represented in the same way (order of bytes used, i.e. endianess) in the same way for different CPU architectures. So the binary file can't be used portably with different computers.
The simplest solution is not to use a binary file, but a text formatted file and overload the std::ostream& operator<<(std::ostream&, const client&) and std::istream& operator>>(std::istream&, client&) output/input operators.
Or use some 3rd party library like boost::serialization or google protocol buffers, that supports de-/serialization to binary files.
So far my only problem with this code is that C won't initialize. I know that if I make degree_type == "C" it won't compile because I can't turn an int into a character. What's exactly wrong with this code?
#include <iostream>
using namespace std;
int main()
{
char C;
double degree;
int degree_type;
cout << "What's the Degree type?: ";
cin >> degree_type;
if (degree_type == C)
{
cout << "What's the Temperature:? ";
cin >> degree;
cout << "Your Degrees in Celsius is, " << 9 / 5 * degree + 32 << " degrees fahrenheit." << endl;
}
else
{
cout << "What's the Temperature:? ";
cin >> degree;
cout << "Your Degrees in Fahrenhait is, " << (degree - 32) * 5 / 9 << " degrees Celsius." << endl;
}
return 0;
}
You are (or were, before you changed your question) using cin to read a character. When you read one character, the next character (the Enter keypress) remains in the input buffer waiting to be read. The next time you read from cin (to get the temperature), it will immediately see the Enter keypress from the previous input and not let you type anything.
Use getline instead:
std::string str;
std::getline(std::cin, str);
degree_type = str.at(0);
Once you have done that, the test degree_type = C does not do what you think it does for two reasons:
The single equals = is assignment. For comparison, use ==.
The C is the name of a variable. For the character C, use 'C'.