Validating the size of array in C - c++

I am facing one issue regarding validating the size of array in C.
We have one .h file, which contains the constant value like
A 1
B 2
C 3
...
...
END 10
last element is END. Whenever any new constant is getting added, value of END should be increased. For e.g. if some added new constant call F which has value 10 then they have to increased the value of END from 10 to 11.
Now, in .c file we have one array of the size END. Each constant defined in .h file should have entry in this array, i.e.
abc[END] = {
1,
2,
1,
0,
...
...
}
Now, we have to add one test to check that, if anyone adding new entry in .h file and they have not added the corresponding entry in abc[] array, then test should fail. Earlier I have written the below piece of code to verify:
return (sizeof(tbl2schema)/sizeof(int) == END) ? TRUE : FALSE;
But I think, this code is not fulfilling the purpose. Hope, I have explained my issue.
Can anyone suggest me on this, How to do this check. I have to add a check that if anyone adding the entry in .h file then they have to add the entry in abc[] array.

The reason that your formula does not work is that you have explicitly specified END as the size. Remove it from the declaration to have the size of abc array change with the number of constants:
int abc[] = {
// ^^
1,
2,
1,
0,
...
...
};
If someone forgets to add a constant after updating END now, the size of abc is not going to match.
Use static_assert to check the condition:
static_assert(sizeof(tbl2schema)/sizeof(int) == END, "abc size does not match.");

It seems the perfect usage for enum :
file.h :
typedef enum { A, B, C, END } constants_list;
file.c :
static int abc[END] = { 1, 2, 1 };
Your table abc will grow automatically as the list of constants grow.
Note however that any value in the table will be initialized to 0 if not explicitly set in file.c.

Maybe you want:
return (sizeof(tbl2schema) / sizeof(int) > END) ? TRUE : FALSE;
which is equivalent of:
return sizeof(tbl2schema) / sizeof(int) > END;

Below is a C solution that does not compile if there is a discrepency between the header and the source file:
Header
enum {
NAME_1,
NAME_2,
NAME_3,
END
};
#define STATIC_ASSERT_ARRAY_SIZE(array, expected_size) \
static int static_assert_array_size_array_##array##_too_small \
[sizeof(array)/sizeof(array[0]) - expected_size]; \
static int static_assert_array_size_array_##array##_too_large \
[expected_size - sizeof(array)/sizeof(array[0])]
Source #1
#include "header.h"
int data[] = { 5, 8 };
STATIC_ASSERT_ARRAY_SIZE(data, END);
int main(void)
{
return 0;
}
Source #2
#include "header.h"
int data[] = { 5, 8, 10 };
STATIC_ASSERT_ARRAY_SIZE(data, END);
int main(void)
{
return 0;
}
Source #3
#include "header.h"
int data[] = { 5, 8, 10, 11 };
STATIC_ASSERT_ARRAY_SIZE(data, END);
int main(void)
{
return 0;
}
Compilation
$ gcc main1.c
main.c:3: error: size of array static_assert_array_size_array_data_too_small is too large
$
$ gcc main2.c
$
$ gcc main3.c
main.c:3: error: size of array static_assert_array_size_array_data_too_large is too large
$
This trick takes advantage from the fact that it is illegal to declare an array of negative size (you don't say !).

I'm assuming you've simplified the example a bit, but it looks like you just have a big array of values that you want to be able to access by name rather than with a "magic number" index—hence the #defines.
If that's the case, why aren't you just using a struct instead, with sequential fields named the same as your current symbolic names for the array indices?
struct { int A, B, C, ... } abc = {
1,
2,
3,
...
};
This way, the compiler will check to make sure you're not accessing an invalid name. You can still iterate over the struct members using pointers:
for (int *p = &abc.A; p <= &abc.Z; abc++) {
do_something_with(*abc);
}

I would like to recommend a more general solution for the problem of interdependent, but scattered data in a program.
It's using a single preprocessor macro file which contains all information in a single place, in the form of a list of preprocessor function macros. The file is included wherever the information is needed to define data structures or types like enums.
In this example I use a list of paper size defintions; this served me nicely in real life when I wrote a PCL6 parser. In PCL6 each paper size is indeed a numerical token. Paper sizes have quite a few associated attributes, as well as a human readable name. Frequently the need occurs to map bidirectionally between name and token value and look up associated information. This leads to several data structures with redundant information plus a matching enum definition. It's easy to miss an update in one of them when adding a new paper type (in reality there are many dozen).
The trick is to define an entry in the macro file to a language construct which is suitable in the given place. Note how the language was carefully designed to allow trailing commas e.g. at the end of an enum definition or initializer lists. This is the use case for that.
We start with the file containing the macros which hold the information associated with a paper size. In reality there are of course many more, and more attributes.
//////////////////////////////////////////////////////
// papermacros.h
//////////////////////////////////////////////////////
// Has all information about paper sizes in one place.
// Note the function syntax. It's essential.
// token, name, height, width
PAPERSIZE_MACRO(5, A5, 200, 150)
PAPERSIZE_MACRO(4, A4, 300, 200)
PAPERSIZE_MACRO(3, A3, 400, 300)
Then the paper class and enum. The macros are used to build an enum type
of paper tokens which always contains all entries in the
macro file. The enum element names are constructed with the preprocessor concatenation operator, names are constructed using the stringize operator. (We cannot have strings in the macro header right away because we want to use the name also as a base for the enum identifier -- there is no "unstringize" operator.)
//////////////////////////////////////////////////////
// papers.h
//////////////////////////////////////////////////////
#include <string>
#include <map>
#include <sstream>
#undef PAPERSIZE_MACRO
#define PAPERSIZE_MACRO(token, name, height, width) \
e_##name = token,
enum PaperSizeE {
e_INVALID, // for default ctor
# undef PAPERSIZE_MACRO
# define PAPERSIZE_MACRO(token, name, height, width) \
e_##name = token,
// this included file expands to a series of enum definitions which
// make sure that each enum element is named
// like the paper name, with a prefix e_
# include "papermacros.h"
e_END // if you want. Note, however, that it has the (arbitrary)
// value of the last "real" enum plus 1.
#undef PAPERSIZE_MACRO
};
class PaperT
{
public:
PaperSizeE token;
int height;
int width;
std::string name;
PaperT(PaperSizeE t, std::string n, int h, int w)
:token(t), name(n), height(h), width(w)
{ }
// Funny, needed by map resp. std::pair
PaperT() : token(e_INVALID), name("invalid"), height(0), width(0)
{}
std::string ToString()
{
std::ostringstream stm;
stm << name << ", height: " << height << ", width: " << width;
return stm.str();
}
};
// Useful mappings. Paper information can now be
// efficiently looked up by token or by name.
extern std::map<PaperSizeE, PaperT> mapByToken;
extern std::map<std::string, PaperT> mapByName;
The next file contains the definitions for the maps declared above. Again the elements of the initiailzer list are constructed from the (multiple times) included macro header, with the respective suitable macro definitions. Here, too, trailing commas are ignored.
//////////////////////////////////////////////////////////////////
// paperdefs.cpp
//////////////////////////////////////////////////////////////////
#include "papers.h"
using namespace std;
std::map<PaperSizeE, PaperT> mapByToken
{
# define PAPERSIZE_MACRO(token, name, height, width) \
{e_##name, PaperT(e_##name, #name, height, width) },
// this expands to a series of
// { e_xx, PaperT(e_xx, "Ax", hhh, www) },
// which is used to initialize the entries a map enum -> paper.
# include "papermacros.h"
# undef PAPERSIZE_MACRO
};
std::map<string, PaperT> mapByName =
{
# define PAPERSIZE_MACRO(token, name, height, width) \
{#name, PaperT(e_##name, #name, height, width) },
// this expands to a series of
// { "Ax", PaperT(e_xx, "Ax", hhh, www) },
// which is used to initialize the entries a map name -> paper.
# include "papermacros.h"
# undef PAPERSIZE_MACRO
};
Last not least a main function in order to demonstrate usage.
//////////////////////////////////////////////////////////////////
// main.cpp
// Demonstrate how to use the paper related data structures.
// Must be linked with paperdefs.o
//////////////////////////////////////////////////////////////////
#include "papers.h"
#include <iostream>
using namespace std;
int main()
{
{
PaperSizeE a4Token = e_A4;
cout << "The name of the paper with token " << a4Token
<< " is " << mapByToken[a4Token].name << endl;
}
{
string name = "A3";
cout << "The token val of the paper named " << name
<< " is " << mapByName[name].token << endl;
}
// iterate over all papers
for(auto &p: mapByName)
{
cout << "Paper by name " << p.first << ": "
<< p.second.ToString() << endl;
}
}
The result:
$ g++ -std=c++11 -o papers main.cpp paperdefs.cpp && ./papers
The name of the paper with token 4 is A4
The token val of the paper named A3 is 3
Paper by name A3: A3, height: 400, width: 300
Paper by name A4: A4, height: 300, width: 200
Paper by name A5: A5, height: 200, width: 150

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++: how to set object from member?

I'm pretty new to C++ and I'm trying to make an interactive virtual shop (not like with real money or anything, just something to practice coding, for possible use in a future game). So far I have defined the class and made it so that each object in the class is defined as fruit# where # is its id number (which is used in an array to define its name)
So basically at this point I have created the proper code to turn the user input into the id number of the fruit, but now I need a way to set the values of the fruit "select" to the values of the fruit that id belongs to.
Essentially, they type "banana," which I can use to arrive at the value 0, and the object "fruit0" corresponds to banana. So how do I get from 0 to fruit0? If this is confusing, let me know and I can try to explain better, but I already feel like I'm rambling...
Here's the (relevant parts of the) code:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
const int fruits=6;
//# of fruits
string names[fruits];
string s;
class fruit {
public:
float weight, price;
int id;
string name;
fruit (float a, float b, string c, int d)
{weight = a; price=b; name=c; names[d]=c;}
};
int main()
{
fruit fruit0 (.5,1,"banana",0);
fruit fruit1 (1.5,3,"pineapple",1);
fruit fruit2 (2,2.5,"coconut",2);
fruit fruit3 (1,1.5,"papaya",3);
fruit fruit4 (4,2,"watermelon",4);
fruit select (0,0,"\0",fruits);
//other, irrelevant code...
}
void ask()
{
cout<<"What would you like to buy? ";
getline (cin,s);
if (s=="select") {dontsell();}
for (i=0;i<fruits;i++)
{if (s==names[i]){select(i);}}
dontsell();
}
void select(int a)
{
//what goes here???
}
I suggest you use std::map<std::string, Fruit>.
You can use the map for storing fruits and their key phrases. It's sort of like a "codename" structure where one value is always associated with another, such as "Banana" to fruit1. Otherwise, I don't really see much of a problem with your question--it's a pretty simple problem which has nice solutions.
You could opt for std::vectors or something, but if you need double vectors that need to be linked by keyword or something, just use std::map.
void ask()
{
cout<<"What would you like to buy? ";
getline (cin,s);
if (s=="select") {dontsell();}
for (i=0;i<fruits;i++)
{
if (s==names[i])
{
// somehow indicate the selected fruit
}
}
dontsell();
}
If I understand correctly, you're asking for advice on how to indicate which fruit object is selected. There are many different ways to do this, but here's one: return the id of the fruit. You also need an array or something to allow you to get the actual fruit object from the id.
int ask() {
// ...
if (s == names[i]) {
return i;
}
// ...
// if nothing matches, return nothing:
return -1;
}
int main() {
fruit fruit_array[fruits] = {
fruit(.5, 1, "banana", 0),
fruit(1.5, 3, "pineapple", 1),
fruit(2, 2.5, "coconut", 2),
fruit(1, 1.5, "papaya", 3),
fruit(4, 2, "watermelon", 4)
};
int selected_id = ask();
if (id > 0) {
std::cout << "You chose " << fruit_array[selected_id].name << '\n';
} else {
std::cout << "You didn't choose anything I recognized.\n";
}
}
Of course, once you do this there are some other changes you would probably want to make. For example there's no reason to have separate arrays names and fruit_array. Here's an example of one way to avoid the duplicate representation of that data.

Need to write a program that takes in at least 4 digits (3453) and prints out: "Three thousands four hundreds 5 tens and 3 ones"

I think I'm on the right track and have all the elements i need, but i'm not too sure how to use classes / token and might have some other things formatted wrong.
#include <string>
#include <iostream>
#include <vector>
using namespace std;
class token {
public:
int value;
string unit;
}
int main() {
token t;
vector<token> v;
string unit = ""
cin>>x;
while (x!=0) {
t.value=x%10;
if (unit==" "}
t.unit = "ones";
else if (unit == "ones")
t.unit = "tens"
else if (unit = "tens")
t.unit = "hundreds"
else if (unit = "hundreds")
t.unit = "thousands"
v.pushback(t);
x=x/10;
}
v_t.push_back("zero")
v_t.push_back("one")
v_t.push_back("two")
v_t.push_back("three")
v_t.push_back("four")
v_t.push_back("five")
v_t.push_back("six")
v_t.push_back("seven")
v_t.push_back("eight")
v_t.push_back("nine")
cout<< "This is ";
for(int i = v.size()-1; i>=0, i--) {
cout<<v_t[v[i].value]<<" "<< v[i].unit << " "}
}
Everything I got here was taken from my notes, but was arranged in a different order. When I try to run it, I get and error message: "New types may not be defined in new types"
There are many compile errors, to take care of the first one, put the semicolon at the end of the class:
class token {
public:
int value;
string unit;
};
For the second one, add a semicolon at the end of the declaration of unit:
string unit = "";
Third one, define "x":
int x;
Fourth, change '}' for ')' here:
if (unit==" ")
There are many more, sorry.
Add semicolons at the ends of all statements to start.
Is it mistyping here or you forget all semicolons? and beside that you write unit = "tens" for comparing unit and "tens"? shouldn't it be unit == "tens"? and to check for empty string replace if( unit = " " ) with if( unit.empty() )
In this assignment, I wouldn't use a std::vector, but a fixed length array.
In C language terms (to show the thought):
struct Text_Entry
{
unsigned int value; // Don't deal with negatives with words.
const char * const text;
};
// Here's the table
struct Text_Entry conversion_table[] =
{
{0, "zero"},
{1, "one"},
{2, "two"},
//...
{10, "ten"},
{11, "eleven"},
//...
{20, "twenty"},
{30, "thirty"},
{40, "forty"},
};
The compiler will load the table for you before your program starts, eliminating the need to use push_back for every case. The value field allows you to arrange the entries in any order.
If you are allowed to, prefer std::map.
Don't use the table for every combination. For example 21 would use the entry for 20 and the entry for 1. Similarly for 135.
HTH.

Getting data from two different arrays for the same index

I created an array like this:
string mobs [5] = {"Skeleton", "Dragon", "Imp", "Demon", "Vampire"};
int mobHP[5] = {10, 11, 12, 13, 14, 15};
I created a random number generator for getting the mob number that i want, but I failed. Supposing, the generated number is 4, how will I equate or equalize it to string mob number 5, and mob hp number 5?
If you have a function that returns a random number between 0 and 4 (Array Indexes) then the code would look something like:
// Since we are using raw arrays we need to store the length
int array_length = 5
// Some function that returns a random number between
int randomIndex = myRandomNumberFunction(array_length)
// Now we select from the array using the index we calculated before
std::string selectedMobName = mobs[randomIndex]
int selectMobHP = mobHP[randomIndex]
However a better way to achieve this using modern C++ practices would be to create a monster class and use it in a vector like so:
#include <vector>
#include <string>
#include <iostream>
// Normally we would use a class with accessors here but for the sake
// of brevity and simplicity we'll use a struct
struct Monster {
Monster(const std::string& in_name, const int in_health) :
name(in_name), health(in_health)
{}
std::string name;
int health;
};
// A vector is like an array that can grow larger if you add stuff to it
// Note: Normally we wouldn't use a raw pointer here but I've used it for
// for the sake of brevity. Instead we would either use a smart pointer
// or we would implement the Monster class with a copy or move constructor.
std::vector<Monster*> monsters;
monsters.push_back(new Monster("Dragon", 5));
monsters.push_back(new Monster("Eelie", 3));
... // Arbitrary number of monsters
monsters.push_back(new Monster("Slime", 1));
// Select a random monster from the array
int random_index = myRandomNumberFunction(monsters.size());
Monster* selected_monster = monsters[random_index];
// Print the monster stats
std::cout << "You encounter " << selected_monster->name << " with "
<< selected_monster->health << "hp" << std::endl;
// Clean up the vector since we're using pointers
// If we were using smart pointers this would be unnecessary.
for(std::vector<Monster*>::iterator monster = monsters.begin();
monster != monsters.end();
++monster) {
delete (*monster);
}
For an array of N elements, the valid indices are in the range of 0 to N-1, where 0 denotes the first element and N-1 denotes the last element.
As you have a generated number in this range, it maps directly onto the elements of the arrays.
If you have the value ix=4, it refers to the fifth monster. You access the name at mobs[ix] and the health at mobHP[ix].

How to get next value of enum

I have the following problem:
enum Language { English, French, German, Italian, Spanish };
int main() {
Language tongue = German;
tongue = static_cast<Language>(tongue + 1);
cout << tongue;
}
//it returns 3.....but i want to get the language name on index 3.....
I find that an explicit look up table works best, for both converting from enum to text and text to enum:
enum Language_Enum
{
LANGUAGE_FIRST = 0,
LANGUAGE_GERMAN = LANGUAGE_FIRST,
LANGUAGE_ENGLISH,
LANGUAGE_HOPI,
LANGUAGE_WELSH,
LANGUAGE_TEXAN,
LANGUAGE_DUTCH,
LANGUAGE_LAST
};
struct Language_Entry
{
Language_Enum id;
const char * text;
};
const Language Entry language_table[] =
{
{LANGUAGE_GERMAN, "German"},
{LANGUAGE_HOPI, "Hopi"},
{LANGUAGE_DUTCH, "Dutch"},
// ...
};
const unsigned int language_table_size =
sizeof(language_table) / sizeof(language_table[0]);
Specifying the enum along with the text, allows for the enum order to change with minimal effect to the search engine.
The LANGUAGE_FIRST and LANGUAGE_LAST identifiers allow for iteration of the enum:
Language_Enum l;
for (l = LANGUAGE_FIRST; l < LANGUAGE_LAST; ++l)
{
// ...
}
You'll have to create an array of strings which matches your enum e.g.
std::string[] LangTxt = { "English", "French", "German", "Italian", "Spanish" };
then you can reference them as follows:
cout << LangTxt[tongue];
Be careful to keep the definitions together though so they are updated side by side.
It is not so simple to print the enum name for a given enum value in C++. Instead, you can use a map or string array to hold the values, which do allow you to get both the index and the string value.
Best Way to use enum is first give initial value to your enum.
enum TestEnum
{
Zero=0,
One,
Two
}
Even you wont specify anything the default starting index is zero.
To get the value at a particular index simple do that
TestEnum(index);