I have written a class that returns a random string after you provide a seed, a sequence length, and a character set as shown below.
I would like to know how to catch any bad input, such as setting the seed to 0 or to a negative number.
The examples that I have seen have just used cout to send an error message and then exit(1); I am thinking about putting a bool flag as a private variable and setting it to false when invalid input is detected. Then after you attempt to generate a random string with this class you would just check that flag through an accessor function.
Is there a better and/or standard way of handling this that will not just exit the program like exit(1)? Any general input about the class is welcomed also. Thanks for the assistance.
RandomString.h
// This is the header file randomstring.h. This is the interface for the class RandomString.
// Values of this type are a random string of the specified length from the specified string character set.
// The values that are needed for input are a positive integer seed, an integer desired length, and a string character set.
// Uses the mt19937 random number engine with a uniform_int_distribution.
#ifndef RANDOMSTRING_H
#define RANDOMSTRING_H
#include <string>
#include <random>
using namespace std;
namespace RandomString
{
class RandomString
{
public:
RandomString(double newSeed, unsigned int newLength, string newCharacterSet); // Initializes the RandomString object with the provided arguments.
RandomString(); // Initializes the seed to 1, the length to 0, and the character set to '0'.
double getSeed();
unsigned int getLength();
string getCharacterSet();
string getSequence();
void setSeed(double newSeed); // Sets the new seed but does not produce a new random sequence.
void setLength(unsigned int newLength); // This is the length of randomSequence.
void setCharacterSet(string newCharacterSet);
void generateNext(); // Generates the next random sequence.
private:
double seed;
unsigned int length;
string characterSet;
string randomSequence;
mt19937 engine;
};
} // RandomString namespace
#endif
RandomString.cpp
// This is the implementation file randomstring.cpp. This is the implementation for the class RandomString.
// The interface for the class RandomString is in the header file randomstring.h.
#include "stdafx.h"
#include <string>
#include <random>
#include "randomstring.h"
using std::string;
using std::uniform_int_distribution;
namespace RandomString
{
RandomString::RandomString(double newSeed, unsigned int newLength, string newCharacterSet)
{
setSeed(newSeed);
setLength(newLength);
setCharacterSet(newCharacterSet);
}
RandomString::RandomString()
{
seed = 1;
length = 0;
characterSet = '0';
}
double RandomString::getSeed()
{
return seed;
}
unsigned int RandomString::getLength()
{
return length;
}
string RandomString::getCharacterSet()
{
return characterSet;
}
string RandomString::getSequence()
{
return randomSequence;
}
void RandomString::setSeed(double newSeed)
{
seed = newSeed;
engine.seed(seed);
}
void RandomString::setLength(unsigned int newLength)
{
length = newLength;
}
void RandomString::setCharacterSet(string newCharacterSet)
{
characterSet = newCharacterSet;
}
void RandomString::generateNext()
{
randomSequence.resize(length);
uniform_int_distribution<> distribution(0,characterSet.length() - 1);
for (int i = 0; i < length; i++)
{
randomSequence[i] = characterSet[distribution(engine)];
}
}
} // RandomString namespace
Finally, here is the test program that I am using.
// test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include "randomstring.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
do
{
double seed = 0;
unsigned int length = 0;
cout << "Enter seed: ";
cin >> seed;
cout << "Enter length of string: ";
cin >> length;
cout << endl;
RandomString::RandomString randomTest(seed,length,"ABCDEFGHJKLMNPQRSTUVWXYZ1234567890");
cout << "class RandomString" << endl;
cout << "seed: " << randomTest.getSeed() << endl;
cout << "length: " << randomTest.getLength() << endl;
randomTest.generateNext();
cout << "random sequence: " << randomTest.getSequence() << endl;
randomTest.generateNext();
cout << "next random sequence: " << randomTest.getSequence() << endl << endl;
}while(true);
}
Throw an exception
void RandomString::setSeed(double newSeed)
{
if (newSeed <= 0) {
throw std::runtime_error("seed should be positive");
}
seed = newSeed;
engine.seed(seed);
}
User would have to use try catch to handle error, else std::terminate is called.
How about letting the user have another chance at giving a good input?
What is the next thing the user will do after they find out they have put in a bad input? There is a high chance they will try again with a good input so just ask for another one.
while(true)
{
cout << "Enter seed: ";
cin >> seed;
if(seed > 0)
{
cout << "ERROR: Seed must be greater than 0." << endl;
break;
}
}
To answer your question about the bool error flag, I wouldn't do it that way. I have no need for bad data that was generated from a bad seed. No data is better than bad data. I generally try to "fail early, fail often", meaning I should stop and report the error as soon as I realize it exists.
If you were set on storing it the error flag, I'd have generateNext() or setSeed return false rather than nothing if there was a problem. Exceptions also work, but are slower and some projects don't like them in C++.
If you plan to have others use RandomString, I'd change the method signature from a double to uint (unsigned int). This would catch negative numbers being used at compile time rather than run time...again helping to fail even earlier. Sounds like this might not work in your classroom scenario, but is a good principle in the real world.
Related
I'm working on a small program that counts up to a number given by the user. The number they enter is stored in the variable limit. I want the number in that variable to be displayed in the title kind of like this: "Counting up to 3000" or "Limit set to 3000" or something like that. I've tried using SetConsoleTitle(limit); and other things but they just don't work. With the code that I have posted bellow, I get the following error:
argument of type "int" is incompatible with parameter of type "LPCWSTR"
I'm currently using Visual Studio 2015 if that's important in any way.
#include <iostream>
#include <windows.h>
#include <stdlib.h>
using namespace std;
int main()
{
begin:
int limit;
cout << "Enter a number you would like to count up to and press any key to start" << endl;
cin >> limit;
SetConsoleTitle(limit); // This is my problem
int x = 0;
while (x >= 0)
{
cout << x << endl;
x++;
if (x == limit)
{
cout << "Reached limit of " << limit << endl;
system("pause");
system("cls");
goto begin;
}
}
system("pause");
return 0;
}
The SetConsoleTitle() function expects a string as its argument, but you're giving it an integer. One possible solution would be to use std::to_wstring() to convert an integer to a wide-character string. C++ string that you get as a result has a different format from the null-terminated wide-character string that SetConsoleTitle() expects, so we need to make the necessary conversion using the c_str() method. So, instead of
SetConsoleTitle(limit);
you should have
SetConsoleTitle(to_wstring(limit).c_str());
Don't forget to #include <string> for to_wstring() to work.
If you want a title that includes more than just a number, you'll need to use a string stream (a wide character string stream in this case):
wstringstream titleStream;
titleStream << "Counting to " << limit << " goes here";
SetConsoleTitle(titleStream.str().c_str());
For string streams to work, #include <sstream>. Here's the full code:
#include <iostream>
#include <string>
#include <sstream>
#include <windows.h>
#include <stdlib.h>
using namespace std;
int main()
{
begin:
int limit;
cout << "Enter a number you would like to count up to and press any key to start" << endl;
cin >> limit;
wstringstream titleStream;
titleStream << "Counting to " << limit << " goes here";
SetConsoleTitle(titleStream.str().c_str());
int x = 0;
while (x >= 0)
{
cout << x << endl;
x++;
if (x == limit)
{
cout << "Reached limit of " << limit << endl;
system("pause");
system("cls");
goto begin;
}
}
system("pause");
return 0;
}
I'm having some problems with my program which I do not understand.
On line 72, I get the error: "error C4700: uninitialized local variable 'sumInEuros' used" however surely it is initialized as I am using it to store a calculation?
Also on line 66 I get "error C4716: 'showPriceInEuros': must return a value" - why must this return a value? the function is simply meant to output a message to the console.
I'm using VS13 and it's c++.
Any help would be very much appreciated, because I am stuck!
Thanks!
#include <iostream> //for cin >> and cout <<
#include <cassert> //for assert
#include <iomanip> //for endl
#include <Windows.h>
using namespace std;
void processAPrice();
int getPriceInPounds();
int convertPriceIntoEuros(int pounds);
int showPriceInEuros(int pounds, int euros);
int calculateSum(int euros);
void produceFinalData(int sum, int numberOfPrices);
int main()
{
char answer('Y');
int numberOfPrices(0);
while (answer = 'Y')
{
processAPrice();
numberOfPrices++;
cout << "Continue? (Y/N)";
cin >> answer;
}
if (numberOfPrices > 0)
//produceFinalData(sum, numberOfPrices);
system("PAUSE"); //hold the screen until a key is pressed
return(0);
}
void processAPrice() //
{
int pounds = getPriceInPounds();
int euros = convertPriceIntoEuros(pounds);
int sum = showPriceInEuros(pounds, euros);
calculateSum(euros);
}
int getPriceInPounds() //
{
int priceInPounds;
cout << "Enter a price (in Pounds): /234";
cin >> priceInPounds;
return priceInPounds;
}
int convertPriceIntoEuros(int priceInPounds) //
{
const int conversionRate(0.82);
return priceInPounds / conversionRate;
}
int showPriceInEuros(int pounds, int euros) //
{
SetConsoleOutputCP(1252);
cout << "The Euro value of /234" << pounds << "is: \u20AC" << euros;
}
int calculateSum(int euros) //
{
int sumInEuros;
sumInEuros = (sumInEuros + euros);
return sumInEuros;
}
void produceFinalData(int sum, int numberOfPrices) //
{
SetConsoleOutputCP(1252);
cout << "The total sum is: \u20AC" << sum;
cout << "The average is: \u20AC" << (sum/numberOfPrices);
}
Well, the showPriceInEuros function is not returning the int it promises to return in its signature. That's the error.
If the function is not supposed to return a value, you should declare its return type as void:
void showPriceInEuros(int pounds, int euros);
//^^
and then:
void showPriceInEuros(int pounds, int euros) {
SetConsoleOutputCP(1252);
cout << "The Euro value of /234" << pounds << "is: \u20AC" << euros;
}
of course.
surely it is initialized as I am using it to store a calculation?
The calculation is based on the variable's uninitialised value:
sumInEuros = (sumInEuros + euros);
^^^^^^^^^^ not initialised
Perhaps you could declare it static, so that its value is preserved between calls to the function, in order to calculate the sum of all the values you pass to the function. Usually, it would be better to use a class to manage persistent data like this, with member functions to update and access it.
why must this return a value?
Because you say it does:
int showPriceInEuros(int pounds, int euros)
^^^
If it shouldn't return a value, change the return type to void.
You do not initialize sumInEuros in this function. You store a result in it - that's true but to calculate the result you are using the uninitialized value.
int calculateSum(int euros) //
{
int sumInEuros;
sumInEuros = (sumInEuros + euros);
return sumInEuros;
}
Answering the question from below:
I would probably create a class PriceCalculator which has all the functions of your algorithm plus the internal state:
class PriceCalculator {
int m_sumInEuros;
public:
PriceCalculator()
: m_sumInEuros(0) { }
void processAPrice(int price);
int getSumInEuros() const { return m_sumInEuros; }
private:
void updateSum(int priceInEuros);
};
From your main function you should create an object of this type and give it the prices you want to sum. Do not do any console input from your class.
int main()
{
PriceCalculator calc;
char answer('Y');
int numberOfPrices(0);
while (answer = 'Y')
{
int priceInPounds;
cout << "Enter a price (in Pounds): /234";
cin >> priceInPounds;
calc.processAPrice(priceInPounds);
numberOfPrices++;
cout << "Continue? (Y/N)";
cin >> answer;
}
...
You might want to think about adding the numberOfPrices to your calculator class as well. At the end you will do all the operations in your class but the user input and console output outside your class. Your class can be tested automatically this way and is completely independent from the user interface.
I am still new to c++ and just started to learn about classes and OOP. I have been practicing trying to make classes out of any item I can think of, so I made a phone class. Code is below. The problem is no matter what number I give it, it displays the same WRONG number everytime. The crazy thing is in the beginning I had given the phone class a variable to store its own number and gave the class instance its own number. That number is the number it keeps wanting to "call". Even after going back several times and making sure I wasn't calling the wring variable I completely deleted the variable and the code still displays the same number. The number is 214-748-3647. Makes me feel like my computer is haunted. Could anyone help?
CODE DOESN'T ACTUALLY MAKE ANY SORT OF PHONE CALL OR ANY CONNECTION WHAT SO EVER
PHONE CLASS HEADER
#ifndef PHONE_H_INCLUDED
#define PHONE_H_INCLUDED
#include <string>
using namespace std;
class Phone{
public:
string Brand;
int Serial;
string CellId;
void Call();
private:
void Dial(int NumberToDial);
void EndCall();
};
#endif // PHONE_H_INCLUDED
PHONE SOURCE CODE
#include <iostream>
#include <string>
#include <sstream>
#include "phone.h"
using namespace std;
void Phone::Call(){
string UserInput = "0";
int NumberToCall = 0;
cout << "What number would you like to call?" << endl << endl;
getline(cin, UserInput);
if(UserInput.length() != 10){
cout << endl << "invalid digits" << endl;
Call();
}
else{
stringstream(UserInput) >> NumberToCall;
Dial(NumberToCall);
}
}
void Phone::Dial(int NumberToDial = 0){
ostringstream converter;
string Number;
converter << NumberToDial;
Number = converter.str();
cout << "Dialing ";
for(int i=0;i<10;i++){
cout << Number[i];
if(i==2){
cout << "-";
}
if(i==5){
cout << "-";
}
}
cout << endl << endl << "Press any key to end the call..." << endl << endl;
cin.get();
EndCall();
}
void Phone::EndCall(){
cout << "Call ended." << endl << endl;
}
Aaaaannnnd my MAIN
#include <iostream>
#include <cstdlib>
#include "phone.h"
using namespace std;
int main()
{
Phone MyPhone;
MyPhone.Brand = "iPhone 5";
MyPhone.CellId = "F2D9G3A2";
MyPhone.Serial = 1411512;
MyPhone.Call();
return 0;
}
This is a very simple answer. You're code and logic is fine. The error occurs because you convert the std::string which holds the phone number to an integer. This is a problem because a typical 10 digit phone number is too big to fit inside the int type. Have a look here to see the min and max numbers you can fit in different types: http://www.cplusplus.com/reference/climits/
Look at this line here actually.
Maximum value for an object of type long int: 2147483647 (231-1) or greater
Funny how the max value is that mysterious phone number.
I am passing a streamstring from one random generator to another to keep track of the current state of an engine (boost random library). It allows me stop at any point and save the current state to reproduce a series later on in the code or continue it.
It works fine until I use different random generators while passing the same stringstream (as reproduce bellow). I cannot use different streams for the two, as in the real example a class will call to different distributions in a random order...
#ifndef RANDOM_HPP
#define RANDOM_HPP
namespace RandomG{
using namespace std;
using namespace boost::random;
int getSeed()
{
ifstream rand("/dev/urandom");
char tmp[sizeof(int)];
rand.read(tmp,sizeof(int));
rand.close();
int* number = reinterpret_cast<int*>(tmp);
return (*number);
}
void Get_Rstream(stringstream &s)
{
mt19937 randgen(getSeed());
s.clear();
s << randgen;
}
template<class distribution>
class Random
{
public:
Random(distribution nd)
{
mt19937 randgen(getSeed());
rng=new variate_generator<mt19937,distribution >(randgen, nd);
}
virtual ~Random()
{
delete rng;
}
void reset(void)
{
(*rng).distribution().reset();
}
double operator()(stringstream &s)
{
double x;
s >> (*rng).engine();
x=(*rng)();
return x;
}
variate_generator<mt19937,distribution > *rng;
};
}
#endif
So now if I instantiate two instances of these classes (below its two uniform but it could be a uniform and a Gaussian or anything else and could be called in a random order).
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/normal_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include "Random.hpp"
using namespace boost::random;
using namespace std;
int main()
{
int M=20;
stringstream ss;
RandomG::Get_Rstream(ss);
string ss2=ss.str();
stringstream ss3;
ss3.clear();
ss3.str(ss.str());
boost::random::uniform_01<> N;
RandomG::Random<boost::random::uniform_01<> > *unif_rand1= new RandomG::Random<boost::random::uniform_01<> >(N);
boost::random::uniform_01<> U;
RandomG::Random<boost::random::uniform_01<> > *unif_rand2=new RandomG::Random<boost::random::uniform_01<> >(U);
(*unif_rand1).reset();
(*unif_rand2).reset();
for(int i=0;i<M;i++)
{
cout << (*unif_rand1)(ss) << " ";
}
for(int i=0;i<M;i++)
{
cout << (*unif_rand2)(ss) << " ";
}
cout <<"\\\\\\\\\\\\\\\\\\\\"<<"\n";
(*unif_rand1).reset();
(*unif_rand2).reset();
for(int i=0;i<M;i++)
{
cout << (*unif_rand1)(ss3) << " ";
}
for(int i=0;i<M;i++)
{
cout << (*unif_rand2)(ss3) << " ";
}
return 0;
}
This should give me two series of the same random numbers, but instead gives me the same random numbers for unif_rand1 but not for unif_rand2.
From what I understood feeding the same state to two different random number generator should give the same result or is there some way to reset them between draws ?
results:
0.525384 0.038626 0.563798 0.705042 0.725001 0.311586 0.843047 0.606338 0.163695 0.437574 \\\\\\\\\\
0.525384 0.038626 0.563798 0.705042 0.725001 0.0566288 0.93966 0.417343 0.686245 0.84118
Thanks for any responses or advises
(the code should be reproducible under linux).
Hello
I know it was asked many times but I hadn't found answer to my specific question.
I want to convert only string that contains only decimal numbers:
For example 256 is OK but 256a is not.
Could it be done without checking the string?
Thanks
The simplest way that makes error checking optional that I can think of is this:
char *endptr;
int x = strtol(str, &endptr, 0);
int error = (*endptr != '\0');
In C++ way, use stringstream:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
stringstream sstr;
int a = -1;
sstr << 256 << 'a';
sstr >> a;
if (sstr.failbit)
{
cout << "Either no character was extracted, or the character can't represent a proper value." << endl;
}
if (sstr.badbit)
{
cout << "Error on stream.\n";
}
cout << "Extracted number " << a << endl;
return 0;
}
An other way using c++ style : We check the number of digits to know if the string was valid or not :
#include <iostream>
#include <sstream>
#include <string>
#include <cmath>
int main(int argc,char* argv[]) {
std::string a("256");
std::istringstream buffer(a);
int number;
buffer >> number; // OK conversion is done !
// Let's now check if the string was valid !
// Quick way to compute number of digits
size_t num_of_digits = (size_t)floor( log10( abs( number ) ) ) + 1;
if (num_of_digits!=a.length()) {
std::cout << "Not a valid string !" << std::endl;
}
else {
std::cout << "Valid conversion to " << number << std::endl;
}
}