I made a small program that generates primes and lets the user check a number and see if it's a prime or not. Problem is, I'm not sure how to properly design it. This is the program:
#include <iostream>
#include <vector>
typedef unsigned long long bigint;
std::vector<bool> sieve(size_t size)
{
std::vector<bool> primelist(size);
primelist[0] = false;
primelist[1] = false;
for (bigint i = 2; i < size; ++i) { primelist[i] = true; }
for (bigint i = 2; i * i < size; ++i)
{
if (primelist[i])
{
for (bigint j = i; j * i < size; ++j)
primelist[i*j] = false;
}
}
return primelist;
}
int main()
{
bigint range;
bigint number;
std::vector<bool> primes;
std::cout << "Enter range: " << std::endl;
std::cin >> range;
primes = sieve(range);
while (1)
{
std::cout << "Enter number to check: " << std::endl;
std::cin >> number;
if (primes[number])
std::cout << "Prime" << std::endl;
else
std::cout << "Not prime" << std::endl;
}
return 0;
}
The basic flow I want to achieve is: Input range, /handle input/, input number to check, /handle input/
I also want to give the user an option to change the range at any given time, by writing a command like "change range number"
I have a few problems with this:
I want the program to be under control if the user inputs a range bigger than unsigned long long, and if the user basically exceeds any limit(like for example if the range he input was 100 then if he checks for 101) an exception will be caught. I know this needs to be implemented using try/catch/throw, but I have no idea how to do that while keeping the option to change the range and without making my code spaghetti code.
Also, I want the errors to be of enum type(I read that enums are good for exceptions), something like
enum errors
{
OUT_OF_RANGE = 1, //Out of the range specified by the user
INCORRECT_VALUE, //If user input "one" instead of 1
RANGE_SIGNED, //If user inputs a signed value for range
NUM_LIMITS //Number exceeds unsigned long long
};
I have no idea how to use exception handling, not to mention using it with enums. How the hell do I keep this program safe and running, while keeping away from spaghetti code?
I am extremely confused. If someone could help me design this program correctly and maintain readability and efficiency, it will really improve my future program designs.
Thanks for reading!
You asked a lot.
You want to validate user input. Users should not be able to enter huge numbers, non-integers, and so on.
I'm going to start off by answering that this is absolutely not a scenario that exceptions should be used for. Exceptions are used to handle exceptional circumstances. These are ones you can't anticipate or really deal with.
A user enters a number that's too big? You can handle that. Tell them that their number is too big, please enter a number between 1 and X.
A user enters the word apple? You can handle that. Tell them that they can only enter integers.
One way of doing this would be to make a ValidateInput function. You can have it return a number (or an enum, they're basically the same thing) to tell you whether there was an error.
In order to do the validation, you will most likely have to receive input as an std::string and then validate it before turning it into a number. Getting input as an unsigned int or similar integral type doesn't really allow you to check for errors.
This adds a bit of work, since you need to manually validate the input manually. There are libraries with functions to help with this, such as boost::lexical_cast, but that's probably too much for you right now.
Below is some very basic psuedo code to illustrate what I mean. It's only meant to give you an idea of what to do, it won't compile or do the work for you. You could extend it further by making a generic function that returns a message based on an error code and so on.
enum error_code {
SUCCESS, // No error
OUT_OF_RANGE, // Out of the range specified by the user
INCORRECT_VALUE, // If user input "one" instead of 1
RANGE_SIGNED, // If user inputs a signed value for range
NUM_LIMITS // Number exceeds unsigned long long
};
// This function will check if the input is valid.
// If it's not valid, it will return an error code to explain why it's invalid.
error_code ValidateInput(const std::string& input) {
// Check if input is too large for an unsigned long long
if (InputIsTooLarge)
return NUM_LIMITS;
// Check if input is negative
if (InputIsNegative)
return RANGE_SIGNED;
// Check if input is not an integer
if (InputIsNotInteger)
return INCORRECT_VALUE;
// If we make it here, no problems were found, input is okay.
return SUCCESS;
}
unsigned long long GetInput() {
// Get the user's input
std::string input;
std::cin >> input;
// Check if the input is valid
error_code inputError = ValidateInput(input);
// If input is not valid, explain the problem to the user.
if (inputError != SUCCESS) {
if (inputError == NUM_LIMITS) {
std::cout << "That number is too big, please enter a number between "
"1 and X." << std::endl;
}
else if (inputError == RANGE_SIGNED) {
std::cout << "Please enter a positive number." << std::endl;
}
else if (inputError == INCORRECT_VALUE) {
std::cout << "Please enter an integer." << std::endl;
}
else {
std::cout << "Invalid input, please try again." << std::endl;
}
// Ask for input again
return GetInput();
}
// If ValidateInput returned SUCCESS, the input is okay.
// We can turn it into an integer and return it.
else {
return TurnStringIntoBigInt(input);
}
}
int main() {
// Get the input from the user
unsigned long long number = GetInput();
// Do something with the input
}
I like Dauphic's answer, particularly because it illustrates breaking down the problem into bits and solving them individually. I would, however, do GetInput a bit differently:
unsigned long long GetInput() {
// Get the user's input
std::string input;
error_code inputError;
// Repeatedly read input until it is valid
do {
std::cin >> input;
inputError = ValidateInput(input);
if (inputError == NUM_LIMITS) {
std::cout << "That number is too big, please enter a number between "
"1 and X." << std::endl;
}
// ...handle all other cases similarly
} while(inputError != SUCCESS);
// If ValidateInput returned SUCCESS, the input is okay.
// We can turn it into an integer and return it.
return TurnStringIntoBigInt(input);
}
The recursive solution is nice, but has the drawback of, well, being recursive and growing the stack. Probably that's not a big deal in this case, but it is something to watch out for.
As for how to write ValidateInput, basically you're going to be scanning the string for invalid characters and if none are found, testing if the value will fit in your chosen integer type until reading it into a variable with e.g. >>.
note: this solution has a serious flaw in that it doesn't check the state of std::cin. If the user were to pass EOF, i.e. press ^D, the program would get stuck in the loop, which is not good behavior.
Instead of a vector of bool you'd better use a bitset
With that, you can use the Eratosthene method to determine if a number is prime or not.
Related
I just started learning to code, starting with C++ yesterday. I need it for a project I'm doing and I like to build generation tools as an "onboarding" process when I learn a new skills. So I thought I'd try building out a regex generation tool.
I googled, I binged, and I looked through the similar questions and only saw answers pertaining to Ruby, Perl, or JS. Frankly, I'm a bit surprised given the utility and prevalence of C++, not more people have tried this.
I don't know how to go about the task, as I'm not a professional or really knowledgeable about what I'm doing. I'm not sure how to ask such questions, either. Please bare with me while I explain my current thoughts.
I am currently toying around with generating strings using byte arrays (I find the C++ type system and casting is confusing at times). I wanted to see if there were any specific ranges of random values that produce strings with latin characters more than others. I get a lot of different values, and found a few ranges that looked like sweet spots, but I ultimately don't know what numbers correlate to what characters.
I wanted to establish a pattern, then set the rand() ranges to correlate with the projected total byte value of what the pattern should generate as a string, then go fishing. I understand that I have to account for upper bounds for characters. So the generated values would be something like:
//not implemented
int getBoundary(string expression){
srand(time(0));
int boundaries[2] = {0};
boundaries[0] = getCeilingValue(expression)
boundaries[1] = getFloorValue(expression)
return boundaries
}
practice.cpp
/*
Method actually producing the byte strings
*/
void practice::stuub(int boundaries[2]){
srand(time(0)); //seed
basic_string<char> byteArray = {}; //"byte array" instantiation
for (int i = 0; i < 1000; i += 1) {
if(i % 2 ==0){
byteArray.push_back(rand() % boundaries[0]);//ceiling
}else{
byteArray.push_back(rand() % boundaries[1]);//floor
}
}
std::string s(byteArray, sizeof(byteArray)); //convert to string
cout << s << "\n";
}
/*
just a copy pasta validation function that I don't know if I need yet
*/
bool isNumeric(string str) {
for (int i = 0; i < str.length(); i++)
if (isdigit(str[i]) == false)
return false; //when one non numeric value is found, return false
return true;
}
/*
current putzing around. It's just been real fun to play around with,
but I plan to replace the instantiation of values of the "mod" array with
the upper/lower bounds of the string projected values This currently takes
a value and just does random stuff to it on a fishing expedition to see
if I can find any patterns.
*/
void practice::randomStringGen() {
try {
srand(time(0));
int mod[2] = {0};
string choice;
while (choice != "q") {
cout << "\n enter an integer to generate random byte strings or press (q) to quit \n";
cin >> choice;
if(choice != "q") {// make sure its not quit, otherwise it still carries out the tasks
if (isNumeric(choice)) {//make sure its numeric
mod[0] = stoi(choice);
if(mod[0] > 0) {//make sure its not 0
mod[0] = int(pow(mod[0], mod[0]));//do some weirdo math
mod[1] = rand() % mod[0]+1; //get another weirdo number
cout << "\n random string start:\n";
stuub(mod);//generate random string
cout << "\n :random string end\n";
}else{//user entered invalid integer
cout << "\n you did not enter a valid integer. Enter numbers greater than 0";
}
}else{
cout << "\n " << choice << " is not an integer";
}
}
}
}catch(std::exception& e){
cout << e.what();
}
}
I hope that provides enough explanation of what I am trying to accomplish.
I'm not any sort of pro, and I have very little understanding of what I'm doing.
I picked this up yesterday as a absolute beginner.
Talk to me like I'm 5 if you can.
Also, any recommendations on how to improve and "discretize" what I'm currently doing would be much appreciated. I think the nested "ifs" look wonky, but that's just a gut instinct.
Thanks!
int main()
{
int sum = 0, value = 0;
while (std::cin >> value)
sum += value;
std::cout << "Sum is: " << sum << std::endl;
return 0;
}
So this code takes values from the user and adds them. I don't understand what makes it reach end of file. I tested it multiple times and found that when I use larger numbers (9999999999) it ends faster, but when I put in just 1s it never ends.
You are experiencing integer overflow.
More specifically, the bool operator on std::istream returns false because the stream failed to read the big value into int.
Blake. The issue is that integers can actually only be so big. The range for a regular int is -32,767 to 32,767; the range of a long int is -2,147,483,647 to 2,147,483,647, etc.. I'm sure there is a list online where you can find the different ranges (I don't have them memorized off the top of my head).
Anyways, I believe your issue is that your int sum is getting too big, and it's breaking your program. Furthermore, I'd recommend having a way to close out of your while loop, so that your program doesn't have the potential to go on forever; you could do this with something like: if(value == -1) break;
Enjoy your studies!
I have a little "blackjack" program coded in C++. The thing is that the program asks questions like "Would you like... (y/n)?" where user needs to type y/n. I want to check if the value returned is actually the type that I want. So function that should return int, returns int and function that should return char, returns char, before it actually returns something.
I would need some suggestions guys. I think it's not that difficult, I just can't find any solution. Thank you.
Code:
char pickCard(){
char aCard;
std::cout << "Would you like another card?";
std::cin >> aCard;
if (aCard is a char){
return aChar;
} else {
std::cout << "Not a char!";
}
}
I think you have a misconception of exactly how std::istream's formatted input works. In your example, aCard must be a char, because you've declared it as such. If the use enters more than one character, one character will be put into aCard, and std::cin will hold onto the other characters and give them to you the next time you call operator>> (or any other input function); if the user enters a number, aCard will be the character representation of the first digit of that number.
Keep in mind that operator>> knows what type of variable you've given it, and it will ensure that the user's input is valid for that type. If you give it an int, it will make sure the users input is convertible to an int or give you 0 if it isn't. A variable can never be anything but the type you declared it to be.
If you're interested in chars in particular, there's a whole bunch of character classification functions you can use to tell what sort of character (letter, digit, whitespace, etc.) you're working with, but keep in mind that char foo('4') is entirely different than int foo(4).
I guess you just want to know if the input string is in number format. >> will set the istream's failbit if it cannot convert the input string to int.
int num;
if (cin >> num) { // input is "123abc", num == 123
cout << "yes, input is a number. At least start with some figures. "
cout << "num == " << num;
} else { // input is "abc" , error
cout << "no, input is not a number or there is some kind of IO error."
}
If you want to force y or n as only allowed characters you can do:
char pickCard(){
std::string response;
std::cout << "Would you like another card?";
std::cin >> response;
if (response=="y" || response=="n"){
return response[0]; //or anything useful
} else {
std::cout << "Not a char!";
//... more code here
}
//... more code here
}
you can use length() property of std::string to find its length. a string of length one is a char in most cases.
This question already has answers here:
Infinite loop with cin when typing string while a number is expected
(4 answers)
Closed 3 years ago.
I'm learning C++ and writing little programs as I go along. The following is one such program:
// This program is intended to take any integer and convert to the
// corresponding signed char.
#include <iostream>
int main()
{
signed char sch = 0;
int n = 0;
while(true){
std::cin >> n;
sch = n;
std::cout << n << " --> " << sch << std::endl;
}
}
When I run this program and keep inputs at reasonably small absolute values, it behaves as expected. But when I enter larger inputs, e.g., 10000000000, the program repetitively spits out the same output. Some combinations of input cause erratic behavior. For example:
#: ./int2ch
10
10 -->
10000000000
10 -->
10 -->
10 -->
10 -->
The program spits out "10 --> " until it's killed. (With this particular sequence of inputs, the program's output changes speed erratically.) I also noticed that the output of large values is determined by the previous legal input as well as the value of the current illegal input.
What's going on? (I don't care about fixing the program, that's easy. I want to understand it.)
Basically your cin stream is in a fail state and thus returns immediately when you try to read it. Rewrite your example like this:
#include <iostream>
int main()
{
signed char sch = 0;
int n = 0;
while(std::cin >> n){
sch = n;
std::cout << n << " --> " << sch << std::endl;
}
}
cin >> n will return a reference to cin, which you can test for "good-ness" in a conditional. So basically the the "while(std::cin >> n)" is saying "while i could still read from standard input successfully, do the following"
EDIT: the reason it repeatedly output the last good value entered is because that was the last value successfully read in n, the failed reads won't change the value of n
EDIT: as noted in a comment, you can clear the error state and try again something like this would probably work and just ignore bad numbers:
#include <iostream>
#include <climits>
int main() {
signed char sch = 0;
int n = 0;
while(true) {
if(std::cin >> n) {
sch = n;
std::cout << n << " --> " << sch << std::endl;
} else {
std::cin.clear(); // clear error state
std::cin.ignore(INT_MAX, '\n'); // ignore this line we couldn't read it
}
}
}
Yes, Evan Teran pointed out most things already. One thing i want to add (since i cannot comment his comment yet :)) is that you must put the call to istream::clear before the call to istream::ignore. The reason is that istream::ignore likewise will just refuse to do anything if the stream is still in the fail state.
Given that you are on a 32 bit machine, 10000000000 is too big a number to be represented by an int. Also converting an int to a char will only give you from 0..255 or -128..127 depending on the compiler.
One problem here is that a char has a size of one byte, and thus can only hold a number between -127 and 128. An int on the other hand, is typically 4 bytes, and can take on much larger values. Second problem is that you are inputting a value that is too large even for an int.
So I am currently learning C++ and decided to make a program that tests my skills I have learned so far. Now in my code I want to check if the value that the user enters is a double, if it is not a double I will put a if loop and ask them to reenter it. The problem I have is how do I go about checking what type of variable the user enters, ex- if a user enters a char or string, I can output an error message. Here is my code:
//cubes a user entered number
#include <iostream>
using namespace std;
double cube(double n); //function prototype
int main()
{
cout << "Enter the number you want to cube: "; //ask user to input number
double user;
cin >> user; //user entering the number
cout << "The cube of " << user << " is " << cube(user) << "." << endl; //displaying the cubed number
return 0;
}
double cube (double n) //function that cubes the number
{
return n*n*n; // cubing the number and returning it
}
Edit: I would have to say I just started and don't have the slightest of clue about your code, but I will check out your link. By the way, I haven't learned how to work with templates yet,I am learning about dealing with data, only Chapter 3 in my C++ Primer Plus 5th edition.
Safe C++ Way
You can define a function for this using std::istringstream:
#include <sstream>
bool is_double(std::string const& str) {
std::istringstream ss(str);
// always keep the scope of variables as close as possible. we see
// 'd' only within the following block.
{
double d;
ss >> d;
}
/* eat up trailing whitespace if there was a double read, and ensure
* there is no character left. the eof bit is set in the case that
* `std::ws` tried to read beyond the stream. */
return (ss && (ss >> std::ws).eof());
}
To assist you in figuring out what it does (some points are simplified):
Creation of a input-stringstream initialized with the string given
Reading a double value out of it using operator>>. This means skipping whitespace and trying to read a double.
If no double could be read, as in abc the stream sets the fail-bit. Note that cases like 3abc will succeed and will not set the fail-bit.
If the fail-bit is set, ss evaluates to a zero value, which means false.
If an double was read, we skip trailing whitespace. If we then are at the end of the stream (note that eof() will return true if we tried to read past the end. std::ws does exactly that), eof will return true. Note this check makes sure that 3abc will not pass our check.
If both cases, right and left of the && evaluate to true, we return true to the caller, signaling the given string is a double.
Similar, you check for int and other types. If you know how to work with templates, you know how to generalize this for other types as well. Incidentally, this is exactly what boost::lexical_cast provides to you. Check it out: http://www.boost.org/doc/libs/1_37_0/libs/conversion/lexical_cast.htm.
C Way One
This way has advantages (being fast) but also major disadvantages (can't generalized using a template, need to work with raw pointers):
#include <cstdlib>
#include <cctype>
bool is_double(std::string const& s) {
char * endptr;
std::strtod(s.c_str(), &endptr);
if(endptr != s.c_str()) // skip trailing whitespace
while(std::isspace(*endptr)) endptr++;
return (endptr != s.c_str() && *endptr == '\0');
}
strtod will set endptr to the last character processed. Which is in our case the terminating null character. If no conversion was performed, endptr is set to the value of the string given to strtod.
C Way Two
One might thing that std::sscanf does the trick. But it's easy to oversee something. Here is the correct way to do it:
#include <cstdio>
bool is_double(std::string const& s) {
int n;
double d;
return (std::sscanf(s.c_str(), "%lf %n", &d, &n) >= 1 &&
n == static_cast<int>(s.size()));
}
std::sscanf will return the items converted. Although the Standard specifies that %n is not included in that count, several sources contradict each other. It's the best to compare >= to get it right (see the manpage of sscanf). n will be set to the amount of the processed characters. It is compared to the size of the string. The space between the two format specifiers accounts for optional trailing whitespace.
Conclusion
If you are a beginner, read into std::stringstream and do it the C++ way. Best not mess with pointers until you feel good with the general concept of C++.
There is no suitable way to check if a string really contains a double within the standard library. You probably want to use Boost. The following solution is inspired by recipe 3.3 in C++ Cookbook:
#include <iostream>
#include <boost/lexical_cast.hpp>
using namespace std;
using namespace boost;
double cube(double n);
int main()
{
while(true)
{
cout << "Enter the number you want to cube: ";
string user;
cin >> user;
try
{
// The following instruction tries to parse a double from the 'user' string.
// If the parsing fails, it raises an exception of type bad_lexical_cast.
// If an exception is raised within a try{ } block, the execution proceeds
// with one of the following catch() blocks
double d = lexical_cast <double> (user);
cout << "The cube of " << d << " is " << cube(d) << "." << endl;
break;
}
catch(bad_lexical_cast &e)
{
// This code is executed if the lexical_cast raised an exception; We
// put an error message and continue with the loop
cout << "The inserted string was not a valid double!" << endl;
}
}
return 0;
}
double cube (double n)
{
return n*n*n;
}
sscanf can do what you want; it returns the number of arguments properly processed. This should get you started:
//cubes a user entered number
#include <iostream>
#include <cstdio>
using namespace std;
double cube(double n); //function prototype
int main()
{
cout << "Enter the number you want to cube: "; //ask user to input number
string user;
cin >> user; //user entering the number
// Convert the number to a double.
double value;
if(sscanf(user.c_str(), "%lf", &value) != 1)
{
cout << "Bad! " << user << " isn't a number!" << endl;
return 1;
}
cout << "The cube of " << user << " is " << cube(user) << "." << endl; //displaying the cubed number
return 0;
}
double cube (double n) //function that cubes the number
{
return n*n*n; // cubing the number and returning it
}
Other methods posted in other answers have their advantages and disadvantages. This one has issues with trailing characters and isn't "C++"-y.
I would have to say I just started and don't have the slightest of clue about your code, but I will check out your link. By the way, I haven't learned how to work with templates yet,I am learning about dealing with data, only Chapter 3 in my C++ Primer Plus 5th edition.
You can fall back on C and use strtod
You program reads in a string and then passes it to a function that attempts to convert the string into double.
bool is_double(const char* strIn, double& dblOut) {
char* lastConvert = NULL;
double d = strtod(strIn, &lastConvert);
if(lastConvert == strIn){
return false;
} else {
dblOut = d;
return true;
}
}