Getter that loops through the variables of a struct - c++

There's a small program that has various options, and these need some input values -- they are in a struct. Each option requires an instance of the struct, so there's an array of struct. I would like to be able to save these options at program exit and read them at program start. But the struct doesn't hold only 3 variables, and they may grow in time as my small program grows. An example of the struct:
struct S
{
int a;
float b;
std::vector<float> c;
}
The save file has as many rows as there are options, and each row contins the same sequence, but different values, which are separated by ;, the elements of the vectors with , and a terminating ;, no spaces. For the above example:
13;3.14;0.618,1.618;
7;2.718;12.3,45.6;
...
But the file can get corrupt, so reading it corrupts the variables and the program crashes. Currently, reading the numbers involves a loop (the number of options/rows is known):
float x;
char c;
std::fstream fs;
// file open, flags, etc
fs >> a >> c;
if(c != ';')
{
std::cerr << "Error! ...\n";
break;
}
fs >> b >> c;
if(c != ';')
{
std::cerr << "Error! ...\n";
break;
}
c = ','; // make sure c is not ';'
while(c != ';')
{
fs >> x >> c;
c.push_back(x);
if(c != ',')
{
std::err << "Error...\n";
break;
}
}
Instead of break it can be an abort() function, or one that starts from scratch, not the problem, but if there are 100 variables, I have to do this for everyone. That's why I was thinking of looping through them. Apparently there's no "reflection" in C++, but it could be done via some macros. Currently, I don't understand either of them, so I tried my own solution. First, I tried making a general use() function with a template, but it fails when called, with template argument deduction/substitution failed. I tried auto as the type, but also fails. I suppose it makes sense. So then I thought why not just make a set/get that handles the worst possible type and converts it, internally. This is what member functions came up:
enum { INT_A, FLOAT_B, VECTOR_C, ALL };
void set(const int &n, const float &f, const int &i = 0)
{
switch(n)
{
case INT_A: a = static_cast<int>(x); break;
case FLOAT_B: b = x; break;
case VECTOR_C: c[i] = x; break;
}
}
float get(const int &n, const int &i = 0)
{
switch(n)
{
case INT_A: return static_cast<float>(a); break;
case FLOAT_B: return b; break;
case VECTOR_C: return c[i]; break;
}
}
get() is mostly for confirming, set() is what interests me. It does seem to work, I can set up a loop to iterate and automate the process, but is this a good solution (I somehow doubt it is, but I am not advanced)? Are there better ones that do not involve external libraries?
Sorry for the delay, I simply forgot to update it. I decided to use an additional std::vector<float> that holds all the variables as float. The order is that the original std::vector<float> (c in the above example) are all, sequentially, last in the vector. The downside is that it occupies about twice as much memory, but less code. Now, I know that the vector c (and the rest in the real case scenario) have a minimum length, so I have two options:
impose the length if the additional vector to include these minimum lengths, then, when it's about writing, I need an if() deciding whether I need to write until the minimum length, or above it, something like this:
if(c.size() < minLength)
// loop to write to c[i]
else
// loop to c.push_back(...)
or I could just consider the length of the additional vector made of the number of single variables, like a and b, and considering the length of the vector (c) zero, thus, when writing, the code will reduce to a for() or while() loop with push_back().
I opted for the second, so the struct now looks like this:
struct S
{
int a;
float b;
std::vector<float> c;
std::vector<float> additional(2); // holds a and b, c islength zero
}
The writing to vector can be easily implemented in a loop. A quick show looks like this:
int n;
float x;
char c;
while(n < maxSizeOfAdditional)
{
switch(n)
{
case 1: a = static_cast<int>(additional[i]); break;
case 2: b = additional[i]; break;
case 3:
{
while(fs >> x >> c)
// loop for writing c.push_back(x)
}
}
++n;
}
I need the original types because of the rest of the code in the program, thus the need for static_cast. It works now, and there is no "reflection", nor did I need one, I just needed a way to automate the process with a loop.
Still, I don't know if it's an "orthodox" approach. For my part, it seems to have solved my problem, but I don't know how something like this would be considered. Better yet, I don't know how "the usual" way is done with programs that need to read/write variables to savefiles, variables that must reside somewhere (I just imagined them in a struct, that's all). I suppose time will tell.

Related

Why does my control function do the opposite of what it's supposed to do?

int control(int n, data a[], string cod){
for(int i = 0 ; i<n ; i++){
if(cod == a[i].code)
return i;
}
return -1;
}
Hello, everyone! this is my control function. it's used to check if a code that has been input by a user already exists in the struct. This is what happens in the "input" function:
void input(int &n, data a[]){
string code;
do{
cout<<"\nInput the code: ";
cin>> code;
if((control(n,a,code))>0)
a[n].code=code;
else
cout<<"\nThe code you've input already exists. Please try again.";
}while((control(n,a,code)) == -1);
n++;
}
There are two problems:
everytime i input a code it tells me that it already exists, even though it's my first time.
it doesn't make me try again, even though the code already exists.
Let's start by indenting your code so we can more easily understand what it does:
int control(int n, data a[], string cod) {
for (int i = 0; i < n; i++)
{
if (cod == a[i].code)
return i;
}
return -1;
}
Ah, so it scans through an array, and returns a value greater than or equal to 0 if a string is present, or -1 if it's absent. Then let's consider the code that uses it:
void input(int &n, data a[])
{
string code;
do
{
cout << "\nInput the code: ";
cin >> code;
if ((control(n, a, code)) > 0)
a[n].code = code;
else
cout << "\nThe code you've input already exists. Please try again.";
} while ((control(n, a, code)) == -1);
n++;
}
So this accepts the code if the return value was greater than 0, and otherwise rejects the code as already existing. This is mostly backwards, but not exactly even that.
My suggestion would be to start by defining an enumeration to give meaningful names to the values you're returning. This makes it much easier to keep track of what's going on:
enum { DUPLICATE, UNIQUE };
int control(int n, data a[], string cod) {
for (int i = 0; i < n; i++)
{
if (cod == a[i].code)
return DUPLICATE;
}
return UNIQUE;
}
Now it's much easier to get our condition correct, and much more obvious if we react to it incorrectly:
if (control(n, a, code) == UNIQUE)
a[n].code = code;
else
cout << "\nThe code is a duplicate";
Or, if you prefer to reverse the condition, it's still easy to get correct:
if (control(n, a, code) == DUPLICATE)
cout << "\nThe code is a duplicate";
else
a[n].code = code;
But in particular, if you accidentally get things backwards, it'll be pretty obvious:
if (contro(n, a, code) == UNIQUE)
cout << "\nThe code is a duplicate";
At least to me, the contrast between "UNIQUE" on one line, and "duplicate" immediately below it seems fairly obvious.
Other Points to Consider
I'd advise against having:
using namespace std;
...in your code, as you apparently do right now. This is a bad habit that saves a little typing now, but can lead to considerable grief in the long term.
I'd also look up std::set and std::unordered_set, which can already do (more efficiently) what you're using your data array to do.
If/when you do need something array-like in C++, you probably want to use an std::array or std::vector rather than the built-in array type. They're much more convenient and help prevent quite a few errors.
I'd try to come up with a better name than control for a function that tries to show whether a code is already in use. control is such a generic name, it's almost impossible to guess what it's supposed to accomplish without looking at its content. A good name for a function does a great deal to clarify the code that uses it, and show what you intend that piece of code to accomplish:
std::cin >> new_code;
if (isDuplicate(new_code))
std::cerr << "The code you entered is a duplicate. Please try again\n";
else
codes.add(new_code);
do{
cout<<"\nInput the code: ";
cin>> code;
if((control(n,a,code))>0)
a[n].code=code;
else cout<<"\nThe code you've input already exists. Please try again.";
}while((control(n,a,code))==-1);
I see at least two problems here:
control returns 0 when the element is found at the first position, you check for >0 in the condition
if the loop body sucessfully inserts the element then while((control(n,a,code))==-1); results in an endless loop.
I suggest you to use std::find_if to check if an element is already present. With a std::vector thats:
#include <string>
#include <vector>
#include <algorithm>
struct data {
std::string code;
};
int main() {
std::vector<data> v;
std::string foo = "test";
auto it = std::find_if(v.begin(),v.end(),[foo](auto x){ return x.code == foo;});
bool found = (it == v.end());
}
Also consider to use a std::set if you want a container with unique entries.

Is there a way to run a statement when a condition in a loop is met at least once?

I am currently doing games on my free time and am currently working on a hangman game. However, I have stumbled upon a problem and I think I could solve it if there was a way to run a statement if a condition inside a loop is met at least once, and if the condition isn't met even once, it'll do another thing. Is it possible to do? Does anyone have any ideas?
I appreaciate any suggestions.
I tried doing something like this:
for (){
if (string [i] == letter that the player inputed){
// replace underscores with the letter guessed
// and also turn a bool statement true
}
else {
// turn the bool statement false
}
}
if (!bool variable){
// print that the letter guessed was not in the answer
// and substract one from the number of guesses available
}
However I noticed that it doesn't work because the loop will run and if the last letter that it checks is not in the answer, the bool will turn false, thus printing that the letter was not in the answer and substracting one from the score. (It's also my first time posting here, and I don't know if that's how I'm supposed to write a code, so I apologize beforehand if I'm not doing it correctly)
`
You should approach this problem from the different angle:
for( ... ) {
if( your condition is met ) {
do_whatever_you_have_to();
break; // <<--- exit the loop, so it's done only once
}
}
You don't have to put flag guessed off if the comparation fails
string s;
bool guessed = false;
char inputted_letter; // comes from somewhere
for (size_t i = 0; i < s.size(); ++i) {
if (s[i] == inputted_letter) {
// replace underscores with the letter guessed
guessed = true;
}
}
if (!guessed) {
// print that the letter guessed was not in the answer
// and substract one from the number of guesses available
}
You don't have to set false in the loop:
bool has_found = false;
for (auto& c : word_to_guess)
{
if (input_letter == c) {
// replace _ by current letter...
has_found = true;
}
}
if (!has_found){
// print that the letter guessed was not in the answer
// and substract one from the number of guesses available
}
But I suggest that your loop does only one thing at a time:
bool contains(const std::string& word_to_guess, char input_letter)
{
return std::any_of(word_to_guess.begin(),
word_to_guess.end(),
[&](char c){ return input_letter == c; })
/*
for (auto& c : word_to_guess)
{
if (input_letter == c) {
return true;
}
}
return false;
*/
}
if (contains(word_to_guess, input_letter)
{
// show current letter...
for (std::size_t i = 0; i != hangman_word.size(); ++i) {
if (word_to_guess[i] == input_letter) {
hangman_word[i] = word_to_guess[i];
}
}
} else {
// print that the letter guessed was not in the answer
// and substract one from the number of guesses available
}
Can you do what you are asking; possibly, however you stated you were making the game Hangman in C++ and I think you are going about this with the wrong approach, therefore, choosing or implementing the wrong algorithms. You are trying to traverse through two strings with possible different lengths from the back end which if it isn't done correctly can lead to issues, will tend to be hard to track especially if their comparisons determine loop conditions, exit or return statements.
I have implemented my version of "Hangman", now albeit the formatting isn't the prettiest, nor are the level dictionaries being generated from a large pool of random words. I express this in the comments of the code that these would generally be read in from a text file and saved into these structures. For simplicity's sake, I initialized them with random words directly in the code.
Take a look to see what I've done:
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <random>
class Game;
int main() {
using namespace util;
try {
Game game("Hangman");
game.start();
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
class Game {
private:
std::string title_;
bool is_running_{ false };
std::string answer_;
std::string guessed_;
std::map<unsigned, std::vector<std::string>> dictionary_; // unsigned represents difficulty level of word
unsigned choosen_difficulty_;
std::string guessed_characters_{"\n"};
public:
Game(const std::string& title) : title_{ title }, choosen_difficulty_{ 0 } {
initialize();
start_over();
}
void start() {
is_running_ = true;
// the player has as many attempts as twice the length of hidden answer's word length.
int number_tries = answer_.size() * 2;
while (is_running_ || number_tries > 0) {
displayGuessedWord();
displayGuessedCharacters();
// ask the player to guess a character;
char guess;
// get a character and make sure it is a valid alphabet character
do {
std::cout << "Guess a character ";
std::cin >> guess;
// Note: I'm using ascii characters in this case
// but for demonstration purposes only!
if ((guess < 'a' && guess > 'z') ||
(guess < 'A' && guess > 'Z')) {
std::cout << "invalid entry ";
}
} while ( (guess < 'a' && guess > 'z') ||
(guess < 'A' && guess > 'Z') );
// test character and update guessed word and number of tries.
test_character(guess);
update_guessed_characters(guess);
number_tries--;
// failed condition
if (number_tries <= 0 && guessed_ != answer_) {
std::cout << "\nGame Over!\n";
is_running_ = try_again(number_tries);
// winning condition
} else if (number_tries > 0 && guessed_ == answer_) {
std::cout << "\nCongratulations!\n";
is_running_ = try_again(number_tries);
}
if (!is_running_) break;
}
}
private:
void displayGuessedWord() {
std::cout << '\n' << guessed_ << '\n';
}
void displayGuessedCharacters() {
std::cout << guessed_characters_ << '\n';
}
void initialize() {
// Normally this would be read in from a file upon game initialization
// but for demonstration purpose, I'll generate a few small vectors of strings
// and associate them to their difficulty level
// levels are based on 3 factors, the length of the word, the repetitive occurance
// of common characters, and the amount of less commonly used characters.
std::vector<std::string> level_1{ "ate", "cat", "dog", "coat", "coal", "does" };
std::vector<std::string> level_2{ "able", "believe", "balloon", "better", "funny", "happy" };
std::vector<std::string> level_3{ "ability", "carpenter", "dogmatic", "hilarious", "generosity", "hostility" };
// ... etc. I'll use just these here for simplicty where each vector has six entries, however,
// with random number generators, this can be done generically for any size
// or number of elements in each of the different vectors.
// create generate the map:
dictionary_[1] = level_1;
dictionary_[2] = level_2;
dictionary_[3] = level_3;
}
std::string getWordFromDictionary(unsigned difficulty, std::map<unsigned, std::vector<std::string>>& dict) {
auto level = dict[difficulty]; // extract the vector based on difficulty level
auto size = level.size(); // get the size of that vector
std::random_device dev; // create a random device
std::mt19937 rng(dev()); // create a pseudo random generator
// create a uniform int distribution type with the range from 0 to size-1
std::uniform_int_distribution<std::mt19937::result_type> dist(0, size - 1);
return level[dist(rng)]; // return a random string from this level.
}
void start_over() {
system("cls"); // Note: I'm running visual studio on Windows!
std::cout << "Welcome to " << title_ << '\n';
// We can use a random generator to pick a word from the given difficulty
// but first we need to get user input for the chosen level.
do {
std::cout << "Choose your difficulty [1-3]\n";
std::cin >> choosen_difficulty_;
if (choosen_difficulty_ < 1 || choosen_difficulty_ > 3) {
std::cout << "Invalid entry:\n";
}
} while (choosen_difficulty_ < 1 || choosen_difficulty_ > 3);
answer_ = getWordFromDictionary(choosen_difficulty_, dictionary_);
// clear and resize guessed word to be that of answer_ and add bunch of hypens.
guessed_.clear();
guessed_.resize(answer_.size(), '-');
// also reset the guessed_characters
guessed_characters_ = std::string("\n");
}
bool try_again(int& tries) {
std::cout << "Would you like to try again?\n";
char c;
std::cin >> c;
if (c == 'y' || c == 'Y') {
start_over();
// don't forget to update this so that the loop can repeat
tries = answer_.size() * 2;
return true;
}
else {
std::cout << "Thank you for playing " << title_ << '\n';
return false;
}
}
void test_character(const char c) {
// here is where you would use the standard library for taking the character
// passed into this function, updating the guessed_characters
// get all indexes
std::vector<unsigned> locations;
for (unsigned i = 0; i < answer_.size(); i++)
if (answer_[i] == c)
locations.push_back(i);
// now update the guessed word
if ( locations.size() > 0 )
for (size_t n = 0; n < locations.size(); n++)
guessed_[locations[n]] = c;
}
void update_guessed_characters(const char c) {
guessed_characters_.insert(0, &c); // just push to the front
}
};
If you noticed how I structured the game class above; I am using while and do-while loops in conjunction with for-loops and if-statements and a single boolean flag to determine the state of the game. The game state is also determined from the update to the guessed characters and guessed word. Then I compare that to the answer. Depending on certain conditions the loop will continue seeking input from the user or will exit.
I am not guaranteeing that this code is 100% bug-free for I didn't do any rigorous testing or checking corner cases or special cases but the code has run without error and I've tested all primary game state cases. It appears to be working fine.
I know that there could be many improvements and simplifications made if I had chosen to use some of the standard library functions for working with strings, but I wanted to illustrate the individual steps that are involved in the design or thinking process of making a game with states and their transitions. I could of also put the game class declaration into its own header file with its implementation in a cpp file, but I left that as a single class that is shown in main.cpp for easy copy and paste and compilation.
With this particular game, I did not use a switch and case statements, I just stuck with some while and do-while loops, a few for loops, and if statements since there are only a few game states and transitions to worry about. This implementation also demonstrates the algorithms that are involved and shows how they interconnect with each other. I hope this helps to give you a better understanding of the design process.
When making a game that has different states with a bit of complexity to it, you should start by making your state table first and list all of its transitions before you even write any code. Then you should list your starting, continuing, winning, failing and exiting states or cases. Then you need to draw up how you would transition from one state to another by their required conditions. This will help you in the long run!
Once you have the game state and its transitions laid out properly, then you can start to make your required functions for those states and begin to connect them together. After that is when you would write the internal of the functions or their implementation of what they would do.
Finally, after you have that down is where you want to do some debugging and unit and case testing and if everything appears to be okay, then it would be safe to improve your current algorithms or choosing better ones for peak or most efficient performance.

how to replace a value of a variable inside code from user input?

i am trying to add a developer mode in my program. since duty of car defers every month,i want give my user permission to change every single variables in my program alike duty lccost yen2taka freight
#include <iostream>
using namespace std;
class A
{
public:
int carbid,duty;
void Input()
{
cout<<"please insert the car price you want to bid for(in yen): ";
cin>>carbid;
cout<<"duty of the car: ";
cin>>duty;
}
int Exportcost()
{
int exportcost;
int servicechrg=10;
int freight=20;
exportcost=servicechrg+freight+carbid;
return exportcost;
}
int Yen2taka()
{
int yen2taka;
int taka2dollarrate=10;
int dollar2yen=1;
yen2taka=((Exportcost())/dollar2yen)*taka2dollarrate;
return yen2taka;
}
int Importcost()
{
int importcost;
int lccost=10;
int cnfcost=20;
importcost=lccost+cnfcost;
return importcost;
}
int Totalcosting()
{
int total;
int myprofit=10; //80000
total=myprofit+Importcost()+Yen2taka();
cout<<total;
return total;
}
void summary()
{
cout<<
}
};
int main()
{
x:
A ob;
ob.Input();
ob.Exportcost();
ob.Yen2taka();
ob.Importcost();
ob.Totalcosting();
int ch;
cout<<"press 1 to see the summery of the costing or 2 to restart costing again"<<endl;
cin>>ch;
switch(ch)
{
case 1:
ob.summary();
break;
case 2:
goto x;
}
}
At first, you should collect these parameters in a separate class:
class Configuration // maybe you find a better name...
{
int m_servicechrg = 10; // default
int m_freight = 20;
// ...
public:
int servicechrg() { return m_servicechrg; }
void servicechrg(int value); { /* check some limits? */ m_servicechrg = value; }
int freight() { return m_freight; }
void freight(int value); { /* check some limits? */ m_freight = value; }
// ...
};
// will allow you to do:
// C c; std::cout << c;
ostream& operator<<(ostream& s, Configuration const& c)
{
// which ever formatting is appropriate...
s << c.servicechrg() << ' ' << c.freight();
return s;
}
The setters could alternatively return bool to indicate invalid values.
Now you can use this class within main:
Configuration c;
A a;
int cost = a.exportCost(c); // you'd have to adjust signatures...
int value;
switch(ch)
{
case 4:
if(stc::cin >> freight) // catches invalid user input!
// one ALWAYS should do, otherwise you might end up in
// your program not working any more
{
c.freight(value);
// or, if you have:
if(!c.freight(value))
{
// some appropriate error message
// (it's better not to output in the setter, you are more flexible this
// way – maybe you want different messages at different occasions?)
}
}
else
{
// appropriate error handling
}
break;
default:
// handling invalid user input
// again, you always should; but stream state is not in error state,
// so you just can print appropriate error message
break;
}
See this answer for how to correctly handle stream errors.
If you wonder about the differences in error handling: First case is met if user enters non-numerical input, such as ss, second case, if input is numerical, but out of valid range (77).
Now if you don't want to pass the configuration as parameter all the time, you could make a global variable from (but careful, there are some dangers with global variables, use them as sparely as possible) or implement the singleton pattern.
Side notes: goto can be a fine tool sometimes, but it is a dangerous one (and the label's name x isn't a good one, prefer a name that clearly shows intention, such as REENTRY_POINT, LOOP_START, ...). If you can get along without unreasonable effort, prefer such variants:
bool isRunning = true;
do
{
// ...
case 2:
isRunning = false;
break;
}
while(isRunning);
Sure, an additional variable, an additional check; unfortunately, you cannot use break to exit a (pseudo-) endless loop (for(;;)) (but don't apply this pattern for nested loops, then it gets more and more unreadabla – and ineffcient: bool isExit = false; for(int i = 0; !isExit && i < n; ++i) { for(j = 0; j < n; ++j) { isExit = true; break; } } – see what I mean?). A variant might be:
for(;;)
{
switch(ch)
case 1:
// ...
//break; <- replace
continue;
case 2:
//
break;
} // end of switch
break; // break the surrounding for(;;) loop
}
But that's not really nice either.
A pretty nice variant allowing to exit the loop in the given case, as there isn't anyhting to do afterwards:
for(;;)
{
switch(ch)
{
case 2:
// maybe yet some cleaning up here
return 0;
default:
// ...
break;
}
}
Drawback: The function's exit point possibly is deeply nested inside the code.
There are yet other tricks to allow this pattern, like packing sub-sections of code in a lambda having a return inside and call that one directly. But that now really starts going beyond the scope...
Finally, if you insist on goto, my variant would rather be:
for(;;)
{
switch(ch)
{
case 2:
// ...
goto LOOP_EXIT;
default:
// ...
break;
}
}
LOOP_EXIT:
return 0; // e. g. main
(void)0; // if there isn't anything to do in the function any more
// (labels require an instruction afterwards!)
There won't be a hidden loop now and it is more obvious what you actually are doing. Currently, not really an issue, but if your code grows, the hidden loop gets more and more difficult to spot.
In such cases, I clearly mark the gotos so that another coder can immediately spot the critical code points:
///////////////////////////////////////////////////
// possibly some comment why applying this pattern
goto SOME_LABEL;
///////////////////////////////////////////////////
One could do the same with deeply nested function exit points (return).

Taking in array of unknown size in c++

Ok I am extremely new to programming, and I am taking a c++ class. Basically for the current project I have to take in an array of unknown size, resize it, and output a bunch of statistics like average, Q1, Q3, etc. I am having trouble taking in the array from the user. I need to quit taking in variables once they enter 0. Here is what I have:
int i = 1; //When I first posted this I didn't mean to comment out the '= 1' part
do {
cin >> array[i];
if (array[i] != 0)
return true;
} while (true);
What am I doing wrong? the program stops after I enter 1 number every time no matter what number I enter.
I am using vector class btw.
Do the following:
// change int to your type
int val;
std::vector<int> vec;
while(std::cin >> val) {
if(val == 0) break;
vec.push_back(val);
}
Reason: Stating a return clause causes to exit the loop.
use of std::vector ensures the arbitrary size condition.
Update after #nonsensickle's constructive remark:
The following piece of code also ensures the only 0 terminates input process condition:
// change int to your type
int val;
std::vector<int> vec;
do {
if(std::cin >> val) {
if(val == 0) break;
vec.push_back(val);
} else { // fix broken input stream in case of bad input
std::cin.clear();
std::cin.ignore(1,'\n');
}
} while(true);
and a more sophisticated way, although overkill but what the hell :), with templates and type traits:
template <typename T>
struct zero_traits
{
static T getzero() { return T(0); }
};
template <>
struct zero_traits<std::string>
{
static std::string getzero() { return "0"; }
};
template <>
struct zero_traits<char>
{
static char getzero() { return '0'; }
};
template <typename T>
std::vector<T> read_values()
{
T val;
std::vector<T> vec;
do {
if(std::cin >> val) {
if(val == zero_traits<T>::getzero()) break;
vec.push_back(val);
} else {
std::cin.clear();
std::cin.ignore(1,'\n');
}
} while(true);
return vec;
}
int main()
{
// change int to your type
std::vector<int> vec = read_values<int>();
for(auto i : vec) std::cout << i << std::endl;
}
First of all i will never increment.
Second of all, if (array[i] != 0) will return if that array's value doesn't equal 0.
You need to read into how do { ... } while() loops work as well as what return statements do. Might as well throw in how to increment an array while you're at it.
I will not try to answer your question directly. What you have is a small logic error and a misunderstanding of the do {...} while () looping construct. What you need is to learn how to step through your code.
Let's go through your code line by line (there are only 6 lines here so it should be really easy):
int i; - Ok, so we are declaring an integer i here but are not giving it a value. As such, i can have a random value.
do { - This is where we will come back to when we evaluate the while clause. But only if the result of the while clause is true.
cin >> array[i] - Store a value that the user enters in the array at the position i. Here we ask ourselves a question, what is i? We should know its value without having to run the program. Hint: there's a problem here because of i
if (array[i] != 0) - If the number entered by the user is not zero return true (exit this function with the result true).
} while (true); - Go back to the do { line and redo all the steps until you get here. There is no condition here so it will keep happening until we exit this function.
Hint: The only exit point of your loop is at step 4.
With this, you should be able to figure out your problem. Trying to break down the problem for yourself should be your first step.
I recommend reading this blog post on debugging small programs. It should be informative.
Though code posted by others (in particular #DimitriosBouzas) will work, and is the better choice, I strongly recommend fixing your code and learning why it failed. This will help you in the long run more than #DimitriosBouzas' elegant solution.
Before answering your question.
Initialize your variables int i=0; .You assign i to be zero because arrays are zero indexed.
You have to incerement i. If do not increment it, i will point at the first "bucket" in your array the whole time. Use i++ or i = i + 1 after every iteration of the do while loop to move "forward" in your array.
You want your program to run until zero is entered so you have to write your condition like this if (array[i] == 0) return true;. This condition is true when the last number entered was zero and it will cause your method to return. It would be more elegant for you to check for it in the while clause.
Putting it all together, your code should look like this
int i=0;
do {
cin >> array[i];
if (array[i] != 0) break;
i++;
} while (i < maxSize);
//do stuff with filled array

Why can't the switch statement be applied to strings?

Compiling the following code gives the error message: type illegal.
int main()
{
// Compilation error - switch expression of type illegal
switch(std::string("raj"))
{
case"sda":
}
}
You cannot use string in either switch or case. Why? Is there any solution that works nicely to support logic similar to switch on strings?
The reason why has to do with the type system. C/C++ doesn't really support strings as a type. It does support the idea of a constant char array but it doesn't really fully understand the notion of a string.
In order to generate the code for a switch statement the compiler must understand what it means for two values to be equal. For items like ints and enums, this is a trivial bit comparison. But how should the compiler compare 2 string values? Case sensitive, insensitive, culture aware, etc ... Without a full awareness of a string this cannot be accurately answered.
Additionally, C/C++ switch statements are typically generated as branch tables. It's not nearly as easy to generate a branch table for a string style switch.
As mentioned previously, compilers like to build lookup tables that optimize switch statements to near O(1) timing whenever possible. Combine this with the fact that the C++ Language doesn't have a string type - std::string is part of the Standard Library which is not part of the Language per se.
I will offer an alternative that you might want to consider, I've used it in the past to good effect. Instead of switching over the string itself, switch over the result of a hash function that uses the string as input. Your code will be almost as clear as switching over the string if you are using a predetermined set of strings:
enum string_code {
eFred,
eBarney,
eWilma,
eBetty,
...
};
string_code hashit (std::string const& inString) {
if (inString == "Fred") return eFred;
if (inString == "Barney") return eBarney;
...
}
void foo() {
switch (hashit(stringValue)) {
case eFred:
...
case eBarney:
...
}
}
There are a bunch of obvious optimizations that pretty much follow what the C compiler would do with a switch statement... funny how that happens.
C++
constexpr hash function:
constexpr unsigned int hash(const char *s, int off = 0) {
return !s[off] ? 5381 : (hash(s, off+1)*33) ^ s[off];
}
switch( hash(str) ){
case hash("one") : // do something
case hash("two") : // do something
}
Update:
The example above is C++11. There constexpr function must be with single statement. This was relaxed in next C++ versions.
In C++14 and C++17 you can use following hash function:
constexpr uint32_t hash(const char* data, size_t const size) noexcept{
uint32_t hash = 5381;
for(const char *c = data; c < data + size; ++c)
hash = ((hash << 5) + hash) + (unsigned char) *c;
return hash;
}
Also C++17 have std::string_view, so you can use it instead of const char *.
In C++20, you can try using consteval.
C++ 11 update of apparently not #MarmouCorp above but http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4067/Switch-on-Strings-in-C.htm
Uses two maps to convert between the strings and the class enum (better than plain enum because its values are scoped inside it, and reverse lookup for nice error messages).
The use of static in the codeguru code is possible with compiler support for initializer lists which means VS 2013 plus. gcc 4.8.1 was ok with it, not sure how much farther back it would be compatible.
/// <summary>
/// Enum for String values we want to switch on
/// </summary>
enum class TestType
{
SetType,
GetType
};
/// <summary>
/// Map from strings to enum values
/// </summary>
std::map<std::string, TestType> MnCTest::s_mapStringToTestType =
{
{ "setType", TestType::SetType },
{ "getType", TestType::GetType }
};
/// <summary>
/// Map from enum values to strings
/// </summary>
std::map<TestType, std::string> MnCTest::s_mapTestTypeToString
{
{TestType::SetType, "setType"},
{TestType::GetType, "getType"},
};
...
std::string someString = "setType";
TestType testType = s_mapStringToTestType[someString];
switch (testType)
{
case TestType::SetType:
break;
case TestType::GetType:
break;
default:
LogError("Unknown TestType ", s_mapTestTypeToString[testType]);
}
The problem is that for reasons of optimization the switch statement in C++ does not work on anything but primitive types, and you can only compare them with compile time constants.
Presumably the reason for the restriction is that the compiler is able to apply some form of optimization compiling the code down to one cmp instruction and a goto where the address is computed based on the value of the argument at runtime. Since branching and and loops don't play nicely with modern CPUs, this can be an important optimization.
To go around this, I am afraid you will have to resort to if statements.
std::map + C++11 lambdas pattern without enums
unordered_map for the potential amortized O(1): What is the best way to use a HashMap in C++?
#include <functional>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
int main() {
int result;
const std::unordered_map<std::string,std::function<void()>> m{
{"one", [&](){ result = 1; }},
{"two", [&](){ result = 2; }},
{"three", [&](){ result = 3; }},
};
const auto end = m.end();
std::vector<std::string> strings{"one", "two", "three", "foobar"};
for (const auto& s : strings) {
auto it = m.find(s);
if (it != end) {
it->second();
} else {
result = -1;
}
std::cout << s << " " << result << std::endl;
}
}
Output:
one 1
two 2
three 3
foobar -1
Usage inside methods with static
To use this pattern efficiently inside classes, initialize the lambda map statically, or else you pay O(n) every time to build it from scratch.
Here we can get away with the {} initialization of a static method variable: Static variables in class methods , but we could also use the methods described at: static constructors in C++? I need to initialize private static objects
It was necessary to transform the lambda context capture [&] into an argument, or that would have been undefined: const static auto lambda used with capture by reference
Example that produces the same output as above:
#include <functional>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
class RangeSwitch {
public:
void method(std::string key, int &result) {
static const std::unordered_map<std::string,std::function<void(int&)>> m{
{"one", [](int& result){ result = 1; }},
{"two", [](int& result){ result = 2; }},
{"three", [](int& result){ result = 3; }},
};
static const auto end = m.end();
auto it = m.find(key);
if (it != end) {
it->second(result);
} else {
result = -1;
}
}
};
int main() {
RangeSwitch rangeSwitch;
int result;
std::vector<std::string> strings{"one", "two", "three", "foobar"};
for (const auto& s : strings) {
rangeSwitch.method(s, result);
std::cout << s << " " << result << std::endl;
}
}
To add a variation using the simplest container possible (no need for an ordered map)... I wouldn't bother with an enum--just put the container definition immediately before the switch so it'll be easy to see which number represents which case.
This does a hashed lookup in the unordered_map and uses the associated int to drive the switch statement. Should be quite fast. Note that at is used instead of [], as I've made that container const. Using [] can be dangerous--if the string isn't in the map, you'll create a new mapping and may end up with undefined results or a continuously growing map.
Note that the at() function will throw an exception if the string isn't in the map. So you may want to test first using count().
const static std::unordered_map<std::string,int> string_to_case{
{"raj",1},
{"ben",2}
};
switch(string_to_case.at("raj")) {
case 1: // this is the "raj" case
break;
case 2: // this is the "ben" case
break;
}
The version with a test for an undefined string follows:
const static std::unordered_map<std::string,int> string_to_case{
{"raj",1},
{"ben",2}
};
// in C++20, you can replace .count with .contains
switch(string_to_case.count("raj") ? string_to_case.at("raj") : 0) {
case 1: // this is the "raj" case
break;
case 2: // this is the "ben" case
break;
case 0: //this is for the undefined case
}
In C++ and C switches only work on integer types. Use an if else ladder instead. C++ could obviously have implemented some sort of swich statement for strings - I guess nobody thought it worthwhile, and I agree with them.
Why not? You can use switch implementation with equivalent syntax and same semantics.
The C language does not have objects and strings objects at all, but
strings in C is null terminated strings referenced by pointer.
The C++ language have possibility to make overload functions for
objects comparision or checking objects equalities.
As C as C++ is enough flexible to have such switch for strings for C
language and for objects of any type that support comparaison or check
equality for C++ language. And modern C++11 allow to have this switch
implementation enough effective.
Your code will be like this:
std::string name = "Alice";
std::string gender = "boy";
std::string role;
SWITCH(name)
CASE("Alice") FALL
CASE("Carol") gender = "girl"; FALL
CASE("Bob") FALL
CASE("Dave") role = "participant"; BREAK
CASE("Mallory") FALL
CASE("Trudy") role = "attacker"; BREAK
CASE("Peggy") gender = "girl"; FALL
CASE("Victor") role = "verifier"; BREAK
DEFAULT role = "other";
END
// the role will be: "participant"
// the gender will be: "girl"
It is possible to use more complicated types for example std::pairs or any structs or classes that support equality operations (or comarisions for quick mode).
Features
any type of data which support comparisions or checking equality
possibility to build cascading nested switch statemens.
possibility to break or fall through case statements
possibility to use non constatnt case expressions
possible to enable quick static/dynamic mode with tree searching (for C++11)
Sintax differences with language switch is
uppercase keywords
need parentheses for CASE statement
semicolon ';' at end of statements is not allowed
colon ':' at CASE statement is not allowed
need one of BREAK or FALL keyword at end of CASE statement
For C++97 language used linear search.
For C++11 and more modern possible to use quick mode wuth tree search where return statement in CASE becoming not allowed.
The C language implementation exists where char* type and zero-terminated string comparisions is used.
Read more about this switch implementation.
I think the reason is that in C strings are not primitive types, as tomjen said, think in a string as a char array, so you can not do things like:
switch (char[]) { // ...
switch (int[]) { // ...
In c++ strings are not first class citizens. The string operations are done through standard library. I think, that is the reason. Also, C++ uses branch table optimization to optimize the switch case statements. Have a look at the link.
http://en.wikipedia.org/wiki/Switch_statement
Late to the party, here's a solution I came up with some time ago, which completely abides to the requested syntax.
#include <uberswitch/uberswitch.hpp>
int main()
{
uswitch (std::string("raj"))
{
ucase ("sda"): /* ... */ break; //notice the parenthesis around the value.
}
}
Here's the code: https://github.com/falemagn/uberswitch
You could put the strings in an array and use a constexpr to convert them to indices at compile time.
constexpr const char* arr[] = { "bar", "foo" };
constexpr int index(const char* str) { /*...*/ }
do_something(std::string str)
{
switch(quick_index(str))
{
case index("bar"):
// ...
break;
case index("foo"):
// ...
break;
case -1:
default:
// ...
break;
}
For quick_index, which doesn't have to be constexpr, you could e.g. use an unordered_map to do it O(1) at runtime. (Or sort the array and use binary search, see here for an example.)
Here's a full example for C++11, with a simple custom constexpr string comparer. Duplicate cases and cases not in the array (index gives -1) will be detected at compile time. Missing cases are obviously not detected. Later C++ versions have more flexible constexpr expressions, allowing for simpler code.
#include <iostream>
#include <algorithm>
#include <unordered_map>
constexpr const char* arr[] = { "bar", "foo", "foobar" };
constexpr int cmp(const char* str1, const char* str2)
{
return *str1 == *str2 && (!*str1 || cmp(str1+1, str2+1));
}
constexpr int index(const char* str, int pos=0)
{
return pos == sizeof(arr)/sizeof(arr[0]) ? -1 : cmp(str, arr[pos]) ? pos : index(str,pos+1);
}
int main()
{
// initialize hash table once
std::unordered_map<std::string,int> lookup;
int i = 0;
for(auto s : arr) lookup[s] = i++;
auto quick_index = [&](std::string& s)
{ auto it = lookup.find(s); return it == lookup.end() ? -1 : it->second; };
// usage in code
std::string str = "bar";
switch(quick_index(str))
{
case index("bar"):
std::cout << "bartender" << std::endl;
break;
case index("foo"):
std::cout << "fighter" << std::endl;
break;
case index("foobar"):
std::cout << "fighter bartender" << std::endl;
break;
case -1:
default:
std::cout << "moo" << std::endl;
break;
}
}
hare's comment to Nick's solution is really cool. here the complete code example (in C++11):
constexpr uint32_t hash(const std::string& s) noexcept
{
uint32_t hash = 5381;
for (const auto& c : s)
hash = ((hash << 5) + hash) + (unsigned char)c;
return hash;
}
constexpr inline uint32_t operator"" _(char const* p, size_t) { return hash(p); }
std::string s = "raj";
switch (hash(s)) {
case "sda"_:
// do_something();
break;
default:
break;
}
In C++ you can only use a switch statement on int and char
cout << "\nEnter word to select your choice\n";
cout << "ex to exit program (0)\n";
cout << "m to set month(1)\n";
cout << "y to set year(2)\n";
cout << "rm to return the month(4)\n";
cout << "ry to return year(5)\n";
cout << "pc to print the calendar for a month(6)\n";
cout << "fdc to print the first day of the month(1)\n";
cin >> c;
cout << endl;
a = c.compare("ex") ?c.compare("m") ?c.compare("y") ? c.compare("rm")?c.compare("ry") ? c.compare("pc") ? c.compare("fdc") ? 7 : 6 : 5 : 4 : 3 : 2 : 1 : 0;
switch (a)
{
case 0:
return 1;
case 1: ///m
{
cout << "enter month\n";
cin >> c;
cout << endl;
myCalendar.setMonth(c);
break;
}
case 2:
cout << "Enter year(yyyy)\n";
cin >> y;
cout << endl;
myCalendar.setYear(y);
break;
case 3:
myCalendar.getMonth();
break;
case 4:
myCalendar.getYear();
case 5:
cout << "Enter month and year\n";
cin >> c >> y;
cout << endl;
myCalendar.almanaq(c,y);
break;
case 6:
break;
}
More functional workaround to the switch problem:
class APIHandlerImpl
{
// define map of "cases"
std::map<string, std::function<void(server*, websocketpp::connection_hdl, string)>> in_events;
public:
APIHandlerImpl()
{
// bind handler method in constructor
in_events["/hello"] = std::bind(&APIHandlerImpl::handleHello, this, _1, _2, _3);
in_events["/bye"] = std::bind(&APIHandlerImpl::handleBye, this, _1, _2, _3);
}
void onEvent(string event = "/hello", string data = "{}")
{
// execute event based on incomming event
in_events[event](s, hdl, data);
}
void APIHandlerImpl::handleHello(server* s, websocketpp::connection_hdl hdl, string data)
{
// ...
}
void APIHandlerImpl::handleBye(server* s, websocketpp::connection_hdl hdl, string data)
{
// ...
}
}
You can use switch on strings.
What you need is table of strings, check every string
char** strings[4] = {"Banana", "Watermelon", "Apple", "Orange"};
unsigned get_case_string(char* str, char** _strings, unsigned n)
{
while(n)
{
n--
if(strcmp(str, _strings[n]) == 0) return n;
}
return 0;
}
unsigned index = get_case_string("Banana", strings, 4);
switch(index)
{
case 1: break;/*Found string `Banana`*/
default: /*No string*/
}
You can't use string in switch case.Only int & char are allowed. Instead you can try enum for representing the string and use it in the switch case block like
enum MyString(raj,taj,aaj);
Use it int the swich case statement.
That's because C++ turns switches into jump tables. It performs a trivial operation on the input data and jumps to the proper address without comparing. Since a string is not a number, but an array of numbers, C++ cannot create a jump table from it.
movf INDEX,W ; move the index value into the W (working) register from memory
addwf PCL,F ; add it to the program counter. each PIC instruction is one byte
; so there is no need to perform any multiplication.
; Most architectures will transform the index in some way before
; adding it to the program counter
table ; the branch table begins here with this label
goto index_zero ; each of these goto instructions is an unconditional branch
goto index_one ; of code
goto index_two
goto index_three
index_zero
; code is added here to perform whatever action is required when INDEX = zero
return
index_one
...
(code from wikipedia https://en.wikipedia.org/wiki/Branch_table)
in many cases you can avid extra work by pulling the first char from the string and switching on that. may end up having to do a nested switch on charat(1) if your cases start with the same value. anyone reading your code would appreciate a hint though because most would prob just if-else-if
Switches only work with integral types (int, char, bool, etc.). Why not use a map to pair a string with a number and then use that number with the switch?