Assigning enum value to integer crashes program [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have created an enum with these values:
enum Car_Manufacturer
{
AUDI = 1,
CHRYSLER = 2,
FORD = 3,
HONDA = 4,
LEXUS = 5,
NISSAN = 6,
MERCEDES = 7,
PORSCHE = 8,
VOLVO = 9
};
I have the user enter a character which corresponds to the model of car they want to view. I need the character the user entered to become a integer which corresponds to the values in the enum so that I can easily search through an array to find a car of the correct make. The function I created looks like this:
int set_car_make_ch( char input )
{
int manufacturer = 0;
if( input == 'A' )
{
manufacturer = AUDI;
}
else if( input == 'C' )
{
manufacturer = CHRYSLER;
}
else if( input == 'F' )
{
manufacturer = (int)FORD;
}
else if( input == 'H' )
{
manufacturer = HONDA;
}
else if( input == 'L' )
{
manufacturer = LEXUS;
}
else if( input == 'M' )
{
manufacturer = MERCEDES;
}
else if( input == 'N' )
{
manufacturer = NISSAN;
}
else if( input == 'P' )
{
manufacturer = PORSCHE;
}
else if( input == 'V' )
{
manufacturer = VOLVO;
}
else
{
cout<<"Invalid Car Manufacturer, please edit the input file."<<endl;
exit( EXIT_FAILURE );
}
return manufacturer;
}
The program freezes and crashes when an enum value attempts to be assigned to an integer. I am using the G++ compiler. Any help with this issue would be greatly appreciated.

Please, use a lookup table or a switch statement rather than the if-else-if ladder.
Lookup Table
struct Car_Text_Enum_Entry
{
const char * name;
Car_Manufacturer enum_value;
};
const static Car_Text_Enum_Entry enum_conversion[] =
{
{"AUDI", AUDI},
{"BMW", BMW},
{"DODGE", DODGE},
//...
};
const unsigned int number_of_conversions =
sizeof(enum_conversion) / sizeof(enum_conversion[0]);
Car_Manufacturer Car_Text_To_Enum(char car_mfg_letter)
{
Car_Manufacturer manufacturer = 0;
for (unsigned int i = 0; i < number_of_conversions; ++i)
{
if (enum_conversion[i].name[0] == car_mfg_letter)
{
manufacturer = enum_conversion[i].enum_value;
break;
}
}
return manufacturer;
}
The lookup table is a lot tighter code and to added or remove manufacturers only requires changing the table, not the code.
Switch Statement
The switch statement approach will work for letters, but not for strings. For strings, use a lookup table.
Car_Manufacturer Car_Mfg_Letter_To_Enum(char car_mfg_letter)
{
Car_Manufacturer manufacturer;
switch (car_mfg_letter)
{
case 'A' : manufacturer = AUDI; break;
case 'B' : manufacturer = BMW; break;
case 'D' : manufacturer = DODGE; break;
case 'H' : manufacturer = HONDA; break;
// ...
}
return manufacturer;
}
The switch statement approach is still more readable and easier to maintain than the if-else-if ladder. However, it will not work with strings (a.k.a. multiple letters).
Maps
However, if you have learned about std::map, you can use it also:
typedef std::map<char, Car_Manufacturer> Car_Mfg_Container;
Car_Mfg_Container car_mfg_association;
// Initialization:
car_mfg_association['A'] = AUDI;
car_mfg_association['B'] = BMW;
//...
Car_Manufacturer Car_Mfg_Letter_To_Enum(char car_mfg_letter)
{
return car_mfg_association[car_mfg_letter];
}
Unlike the static, constant, lookup table, the std::map must be initialized during runtime.
So, please, don't use if-else-if ladders for things that can be looked up in a table.
Also, with enumerations, you only need to assign a value to the first item.

You have not explained what (if any...) error message you are getting or how you are using this function, but it's generally not a good idea to rely implicit or C style casting from enum to int when you have better tools available in C++:
Try this: Declare your variable as type Car_Manufacturer:
Car_Manufacturer manufacturer{};
If for some reason you must use int try this:
manufacturer = static_cast < int >(FORD);
If there is something else wrong, instead of just crashing because you're doing an explicit, C style cast, you should get a reasonable error message from static_cast.
The best way to avoid such issues entirely is to use C11's Scoped enumerations, which are strongly typed and cannot simply be cast as integers.
(As an aside, as #ThomasMatthews has explained, use switch, not if/else if when you have an enum, char or int.)

Related

How to deduce enum elements?

I need to write a spell book and I have two ways to do it - use enum, or use std :: map, as it is easier for me to use enum. But I ran into a problem how to display my enum?
I want to make it so that I can display all these spells on the screen and ask the user which of these spells do you want to use?
for example:
enum Book {
Tornado,
FireBall,
etc,
};
I want it to be output to the console like this :
choose one:
1.Tornado
2.FireBall
how to output this,for example with using array,is it possible?
If you want to display the enum (Tornado, FireBall) instead of 1, 2 you can create a separate function doing that display
#include <iostream>
enum Book {
Tornado,
FireBall,
};
void yourFunction(const Book& book)
{
switch(book)
{
case Book::Tornado:
std::cout<<"Tornado"<<std::endl;
break;
case Book::FireBall:
std::cout<<"FireBall"<<std::endl;
break;
default:
break;
}
}
int main()
{
Book b=Book::FireBall;
yourFunction(b);
return 0;
}
The general problem described here is associating a known integer value with a text string. The solution can be as straightforward as this:
enum Book {
Tornado,
Fireball,
last_index // see below
};
static const char* names[] = {
"Tornado",
"Fireball"
};
To display the menu, just go through the enumerators:
for (int i = Tornado; i < last_index; ++i)
std::cout << (i + 1) << '.' << names[i] << '\n';
You can do this because enumerators start at 0 and increase by 1, that is, the value of Tornado is 0 and the value of Fireball is 1. The value of last_index is 2.
The reason for using last_index is to make it easier to maintain the code. If you add an enumerator that loop doesn't change:
enum Book {
Tornado,
Fireball,
GladHands,
last_index // see below
};
static const char* names[] = {
"Tornado",
"Fireball",
"Glad Hands"
};
With the added enumerator, the value of GladHands is 2 and the value of last_index is 3, so the original loop still works.
Note that this does not generate text from the name of the enumerator. The name of the enumerator has restrictions on it that the text version doesn't, so you really can't generate text in most cases. In particular, GladHands has no spaces, but its text version has one.

C++ Return either a string or int without auto [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I am writing an SQL controller with a Column class. The Column class has properties
Name (string)
Type (enum list)
Index (in row)
Value
But values can be strings or ints. In reality, in sqlite anyway, all values are returned as char arrays. But in the end I want the user to be able to do something like
Column column = row->GetColumn(1);
value = column->GetValue();
Now I don't have access to auto so I'm not even sure how to handle this on any level, neither from the caller (how do they necessarily know what the value type is?) and from the Column class.
Have GetValue() return a std::variant (or boost::variant if you are using a pre-C++17 compiler) that is populated with the correct data based on the actual SQL type. Then the caller can extract data from the variant based on what is actually stored in it:
typedef std::variant<std::monostate, int, std::string, and_so_on...> SQLValue;
...
SQLValue value = column->GetValue();
if (std::holds_alternative<std::monostate>(value))
{
// you can use this for null data...
}
else if (std::holds_alternative<int>(value))
{
int ivalue = std::get<int>(value);
...
}
else if (std::holds_alternative<std::string>(value))
{
std::string svalue = std::get<std::string>(value);
...
}
else ...
Alternatively:
SQLValue value = column->GetValue();
if (std::get_if<std::monostate>(&value))
{
// you can use this for null data...
}
else if (int *p_ivalue = std::get_if<int>(&value))
{
int ivalue = *p_ivalue;
...
}
else if (std::string *p_svalue = std::get_if<std::string>(&value))
{
std::string svalue = *p_svalue;
...
}
else ...
Alternatively:
SQLValue value = column->GetValue();
switch (value.index())
{
case 0:
{
// you can use this for null data...
break;
}
case 1:
{
int ivalue = get:::get<1>(value);
...
break;
}
case 2:
{
std::string svalue = std::get<2>(&value);
...
break;
}
case ...
}

How to make sure user enters allowed enum

I have to write a program with an Enum state, which is the 50 2-letter state abbreviations(NY, FL, etc). I need to make a program that asks for the user info and they user needs to type in the 2 letters corresponding to the state. How can I check that their input is valid i.e matches a 2 letter state defined in Enum State{AL,...,WY}? I suppose I could make one huge if statement checking if input == "AL" || ... || input == "WY" {do stuff} else{ error input does not match state }, but having to do that for all 50 states would get a bit ridiculous. Is there an easier way to do this?
Also if Enum State is defined as {AL, NY, FL}, how could I cast a user input, which would be a string, into a State? If I changed the States to {"AL", "NY", "FL"} would that be easier or is there another way to do it?
Unfortunately C++ does not provide a portable way to convert enum to string and vice versa. Possible solution would be to populate a std::map<std::string,State> (or hash map) and on conversion do a lookup. You can either populate such map manually or create a simple script that will generate a function in a .cpp file to populate this map and call that script during build process. Your script can generate if/else statements instead of populating map as well.
Another, more difficult, but more flexible and stable solution is to use compiler like llvm and make a plugin that will generate such function based on syntax tree generated by compiler.
The simplest method is to use an STL std::map, but for academic exercises that may not be permitted (for example it may be required to use only techniques covered in the course material).
Unless explicitly initialised, enumerations are integer numbered sequentially starting from zero. Given that, you can scan a lookup-table of strings, and cast the matching index to an enum. For example:
enum eUSstate
{
AL, AK, AZ, ..., NOSTATE
} ;
eUSstate string_to_enum( std::string inp )
{
static const int STATES = 50 ;
std::string lookup[STATES] = { "AL", "AK", "AZ" ... } ;
int i = 0 ;
for( i = 0; i < STATES && lookup[i] != inp; i++ )
{
// do nothing
}
return static_cast<eUSstate>(i) ;
}
If perhaps you don't want to rely on a brute-force cast and maintaining a look-up table in the same order as the enumerations, then a lookup table having both the string and the matching enum may be used.
eUSstate string_to_enum( std::string inp )
{
static const int STATES = 50 ;
struct
{
std::string state_string ;
eUSstate state_enum ;
} lookup[STATES] { {"AL", AL}, {"AK", AK}, {"AZ", AL} ... } ;
eUSstate ret = NOSTATE ;
for( int i = 0; ret == NOSTATE && i < STATES; i++ )
{
if( lookup[i].state_string == inp )
{
ret = lookup[i].state_enum ;
}
}
return ret ;
}
The look-up can be optimised by taking advantage of alphabetical ordering and performing a binary search, but for 50 states it is hardly worth it.
What you need is a table. Because the enums are linear,
a simple table of strings would be sufficient:
char const* const stateNames[] =
{
// In the same order as in the enum.
"NY",
"FL",
// ...
};
Then:
char const* const* entry
= std::find( std::begin( stateNames ), std::end( stateNames ), userInput );
if (entry == std::end( stateNames ) ) {
// Illegal input...
} else {
State value = static_cast<State>( entry - std::begin( stateNames ) );
Alternatively, you can have an array of:
struct StateMapping
{
State enumValue;
char const* name;
struct OrderByName
{
bool operator()( StateMapping const& lhs, StateMapping const& rhs ) const
{
return std::strcmp( lhs.name, rhs. name ) < 0;
}
bool operator()( StateMapping const& lhs, std::string const& rhs ) const
{
return lhs.name < rhs;
}
bool operator()( std::string const& lhs, StateMapping const& rhs ) const
{
return lhs < rhs.name;
}
};
};
StateMapping const states[] =
{
{ NY, "NY" },
// ...
};
sorted by the key, and use std::lower_bound:
StateMapping::OrderByName cmp;
StateMapping entry =
std::lower_bound( std::begin( states ), std::end( states ), userInput, cmp );
if ( entry == std::end( states ) || cmp( userInput, *entry) {
// Illegal input...
} else {
State value = entry->enumValue;
// ...
}
The latter is probably slightly faster, but for only fifty
entries, I doubt you'll notice the difference.
And of course, you don't write this code manually; you generate
it with a simple script. (In the past, I had code which would
parse the C++ source for the enum definitions, and generate the
mapping functionality from them. It's simpler than it sounds,
since you can ignore large chunks of the C++ code, other than
for keeping track of the various nestings.)
The solution is simple, but only for 2 characters in the string (as in your case):
#include <stdio.h>
#include <stdint.h>
enum TEnum
{
AL = 'LA',
NY = 'YN',
FL = 'LF'
};
int _tmain(int argc, _TCHAR* argv[])
{
char* input = "NY";
//char* input = "AL";
//char* input = "FL";
switch( *(uint16_t*)input )
{
case AL:
printf("input AL");
break;
case NY:
printf("input NY");
break;
case FL:
printf("input FL");
break;
}
return 0;
}
In above example I used an enumeration with a double character code (it is legal) and passed to the switch statement a input string. I tested it end work!. Notice the word alignment in enumeration.
Ciao

To find duplicate entry in c++ using 2D Vector (std::vector)

I wrote a program to find duplicate entry in a table. I am a beginner in C++, hence I don't know how this program is working efficient. Is there any other idea to write this program? Here I have 3 tables (2D Vector), that they are 1)aRecord_arr 2)mainTable and 3)idxTable. idxtable is use to identify the keys to check duplicate entry. aRecord_arr table to be add in maintable. If it is already exist in maintable, it will show the error "Duplicate Entry". So Check this program, and give your suggestions.
typedef vector<string> rec_t;
typedef vector<rec_t> tab_t;
typedef vector<int> cn_t;
int main()
{
tab_t aRecord_arr= { {"a","apple","fruit"},
{"b","banana","fruit"} };
tab_t mainTable = { {"o","orange","fruit"},
{"p","pineapple","fruit"},
{"b","banana","fruit"},
{"m","melon","fruit"},
{"a","apple","fruit"},
{"g","guava","fruit"} };
tab_t idxTable = { {"code","k"},
{"name","k"},
{"category","n"}};
size_t Num_aRecords = aRecord_arr.size();
int idxSize = idxTable.size();
int mainSize = mainTable.size();
rec_t r1;
rec_t r2;
tab_t t1,t2;
cn_t idx;
for(int i=0;i<idxSize;i++)
{
if(idxTable[i][1]=="k")
{
idx.push_back(i);
}
}
for(size_t j=0;j<Num_aRecords;j++)
{
for(unsigned int id=0;id<idx.size();id++)
{
r1.push_back(aRecord_arr[j][idx[id]]);
}
t1.push_back(std::move(r1));
}
for(int j=0;j<mainSize;j++)
{
for(unsigned int id=0;id<idx.size();id++)
{
r2.push_back(mainTable[j][idx[id]]);
}
t2.push_back(std::move(r2));
}
for(size_t i=0;i<t1.size();i++)
{
for(size_t j=0;j<t2.size();j++)
{
if(t1[i]==t2[j])
{
cout<<"Duplicate Entry"<<endl;
exit(0);
}
}
}
}
If you want to avoid duplicate entries in an array, you should consider using a std::setinstead.
What you want is probably a std::map or a std::set
Don't reinvent the wheel, the STL is full of goodies.
You seem to be rooted in a weakly typed language - but C++ is strongly typed.
You will 'pay' the disadvantage of strong typing almost no matter what you do, but you almost painstakingly avoid the advantage.
Let me start with the field that always says 'fruit' - my suggestion is to make this an enum, like:
enum PlantType { fruit, veggie };
Second, you have a vector that always contain 3 strings, all with the same meaning. this seems to be a job for a struct, like:
struct Post {
PlantType kind;
char firstchar;
string name;
// possibly other characteristics
};
the 'firstchar' is probably premature optimization, but lets keep that for now.
Now you want to add a new Post, to an existing vector of Posts, like:
vector<Post> mainDB;
bool AddOne( const Post& p )
{
for( auto& pp : mainDB )
if( pp.name == p.name )
return false;
mainDB.push_back(p);
return true;
}
Now you can use it like:
if( ! AddOne( Post{ fruit, 'b', "banana" } ) )
cerr << "duplicate entry";
If you need speed (at the cost of memory), switch your mainDB to map, like:
map<string,Post> mainDB;
bool AddOne( const Post& p )
{
if( mainDB.find(p.name) != mainDB.end() )
return false;
mainDB[p.name]=p;
return true;
}
this also makes it easier (and faster) to find and use a specific post, like
cout << "the fruit is called " << mainDB["banana"].name ;
beware that the above will cause a runtime error if the post dont exists
As you can see, firstchar was never used, and could be omitted. std::map
has a hash-function-specialization for string keys, and it will probably be
orders of magnitude faster than anything you or I could whip up by hand.
All of the above assumed inclusion of the correct headers, and
using namespace std;
if you dont like using namespace, prepend std:: to all the right places
hope it helps :)

Branching without if statement

Is it possible to branch code without using an if statement?
Yes, you can, GPU-style.
Say you have a function that branches, and returns a value at the end.
float function( float input )
{
if( input > 0 )
{
// do stuff
finalValue = 2+4+8*input;
return finalValue ;
}
else
{
// do other stuff
finalValue = 1+input;
return finalValue ;
}
}
To do this without branching, you can write the code GPU-style: that is, evaluate both branches, then throw away the one you don't want at the end.
float function( float input )
{
// do stuff..regardless
finalValue1 = 2+4+8*input;
// do other stuff..regardless
finalValue2 = 1+input;
bool resultMask = input > 0 ; // 1 if should use finalValue1.
return finalValue1*resultMask + finalValue2*(1 - resultMask) ;
}
So there you have it. Branching without branching, if statements without if statementing.
Depends on what you mean by "branch" and "if". Any of the below branch, with no "if".
switch (foo) {
}
Or ternary operators, if you don't count:
x == 0 ? doFunc1() : doFunc2()
If your language supports function pointers:
funcArray[selectedOption]()
You can be silly and do:
boolean once = true;
while (condition && once) {
doAWhichNeverReturns();
once = false;
}
doB();
But I don't think this really answers your question, because I don't know what you're trying to do.
I was thinking about that because in mindastry game there is no dynamic if-statements, its simple script.
If you know adresses, you can use a max function:
0: set adressFalse = 5;
1: set adressTrue = 7;
2: set boolean // 0 or 1
3: adress = max (adressTrue * boolean, adressFalse) // 7 or 5
4: goto adress
5: print("false");
6: goto 8
7: print("true");
8: // next code
Pay attention: goto input isnt a expression here.