Give me a hint or (Answer) for vector initialization - c++

Im really sad that I have no idea what and how to do .
I have this,
struct TeamS
{
int ID;
string MEMBERS[3];
};
void Initialize (vector <TeamS> & TeamV, const int id[],
const string m[][NUM_MEMBERS], int arraySize);
int main()
{
vector <string> TeamV;
//not sure TeamV is supposed to be int or string
const int ID[NUM_TEAMS] = { 123, 321, 456, 789 };
const string MEMBERS[NUM_TEAMS][NUM_MEMBERS] =
{
{ "Sarah", "Joe", "John" },
{ "Chris", "Kevin", "James" },
{ "Tom", "Kim", "Emily" },
{ "Jill", "Jason", "Jim" }
};
cout << "Starting Initialization" << endl;
cout << "Ending Initialization" << endl;
}
I have to use this prototype
which is :
void Initialize (vector <TeamS> & TeamV, const int id[],
const string m[][NUM_MEMBERS], int arraySize);
to pass in the empty vector and the arrays
For example,
the first element of the vector will have team id: 123 and members: Sarah, Joe, and John.
The second element of the vector will have team id: 321 and members: Chris, Kevin, and James, and so on.
How can I do this??
DO I have to use push_back ??
or is it much easier than I think??

I think you want to make TeamV a vector of type TeamS, so each element in TeamV can contain information about a team (ID and MEMBERS). Using the push_back() method is sounds like a great idea, try it out

vector <string> TeamV; ==> This has to be 'vector<TeamS> TeamV;'
To add elements to vector, first you need to construct individual entries.
Something like:
TeamV.push_back(TeamS());
TeamV[0].ID = id[0];
std::copy(m[0], m[0] + NUM_MEMBERS, TeamV[0].MEMBERS);

Related

how to convert object type to int c++

I am trying to create a sort of record list using two classes. One class is for entering the values while other class is for gathering them, organizing them, and printing them. Here is my code:
class enterrecords
{
public:
string name;
int age;
string birthmonth;
enterrecords()
{
name = "";
age = 0;
birthmonth = "";
}
enterrecords(string n, int a, string b)
{
name = n;
age = a;
birthmonth = b;
}
};
class records
{
public:
vector <enterrecords> list;
records()
{
}
records(enterrecords s)
{
}
void addtolist(const enterrecords s)
{
this->list.push_back(s);
}
void print()
{
for (const auto& it : this->list)
{
cout << it.name << " " << it.age << " " << it.birthmonth << endl;
}
}
};
int main()
{
enterrecords s1;
enterrecords s2;
enterrecords s3;
records c1;
s1 = enterrecords("john", 21, "jan");
s2 = enterrecords("male", 25, "feb");
s3 = enterrecords("rob", 23, "oct");
c1.addtolist(s1);
c1.addtolist(s2);
c1.addtolist(s3);
c1.print();
}
Here is the output of this program:
john 21 jan
male 25 feb
rob 23 oct
ultimately, I want to be able to organize this list by age from youngest to oldest. so after rearranging them, here is what it would look like after:
john 21 jan
rob 23 oct
male 25 feb
I tried to conventionally sort them, but the problem is, "21" "23" and "25" are not int values but object values. Is there any way to convert them into int so that I could do some operations and sort them? Thank you.
std::sort is normally used to sort a sequence of objects. Either the class has a natural order and then you make an operator< function for it (and preferably also the other boolean comparison operators) or else you pass a comparator function to std::sort that can be a lambda for simple comparisons like comparing one or two member-variables.
Example based on your code (not compiled/tested) that doesn't take the month into account, because you made it a bit more difficult for an example:
std::sort(c1.list.begin(), c1.list.end(), [](const auto& r1, const auto& r2) { return r1.age < r2.age; });

Store dynamic amounts of data in a class C++

I have a class that stores data and within the class I have an array called 'position' that stores strings of 2 characters. Unfortunately, the amount of 2 character strings it should hold will vary:
class shipStatus
{
public:
char* name;
int x{};
char position[x][2]; // does not work
void setInfo(char name[], int x);
void displayStatus();
};
The setInfo function assigns a numerical value to x, which varies among objects. I would like the value of x to also dictate the length of the character array 'position'.
For example:
if x = 3 then
char position[3][2]; // the length of the second array is always 2
How can I make my code do this? If I try adding a variable as the parameters my code does not compile.
Here is my setInfo function:
void shipStatus::setInfo(char name[], int x)
{
name = name;
x = x;
}
Since this is C++, you should use the C++ facilities that are available to you. In your case, it would be std::string, std::vector, and std::array.
Below is an example using basically what your original shipStatus structure consisted of, and changing it to using the above mentioned constructs:
#include <string>
#include <array>
#include <vector>
#include <iostream>
class shipStatus
{
std::string name; // <-- Replaced char*
std::vector<std::array<char, 2>> position; // <-- A vector of an array that has a size of 2
public:
void setInfo(std::string n, int x);
void displayStatus();
void setPosition(size_t whichItem, char c1, char c2);
size_t getNumPositions() const;
};
void shipStatus::setInfo(std::string n, int x)
{
name = n;
position.resize(x); // <-- All we need to do is resize() to dynamically resize the vector
}
void shipStatus::displayStatus()
{
for (auto& p : position)
std::cout << p[0] << " " << p[1] << "\n";
}
void shipStatus::setPosition(size_t whichItem, char c1, char c2)
{
position[whichItem] = {c1, c2}; // <-- we set one item in the vector, and in
// that item, we set the [0] and [1] characters
}
size_t shipStatus::getNumPositions() const { return position.size(); }
int main()
{
shipStatus sStatus;
sStatus.setInfo("Ship 1", 3);
sStatus.setPosition(0, '4', '2');
sStatus.setPosition(1, 'a', 'b');
sStatus.setPosition(2, 'y', 'z');
std::cout << "Number of positions: " << sStatus.getNumPositions() << "\n";
sStatus.displayStatus();
}
Output:
Number of positions: 3
4 2
a b
y z
Note that we no longer need x as a member, since a std::vector knows its size already by calling the size() member function.
char **position;
position = (char **)malloc(sizeof(char *)*x);
for (int i=0; i<x; ++i)
{
position[i] = (char *)malloc(sizeof(char)*2);
}
This is a classic "C" way of doing it, will work in C++ too.
For a cleaner approach, we should use vectors/lists for this purpose.

How to fill array of struct containing pointer arrays

I have an small and quite simple issue in C++. I want to fill array of struct containing double arrays. How can I do that?
typedef struct
{
double *inputs[2];
double *target[1];
} Data;
Data data[]
{
new double[2]{10, 20}, new double[1]{30},
new double[2]{40, 50}, new double[1]{60},
new double[2]{70, 80}, new double[1]{90},
new double[2]{100, 110}, new double[1]{120}
};
and in the main()
printf("data[0]: inputs: %f %f, targets: %f\n",
*data[0].inputs[0],
*data[0].inputs[1],
*data[0].target[0]);
This is my idea, but when I run that it will print this:
data[0]: inputs: 10.000000 30.000000, targets: 40.000000
Of course, at the end of the array data (like 3rd or 4th item) it will cause UNAUTHORIZED ACCESS TO MEMORY
Thank you for your ideas and patience ;)
Using modern c++ makes your code both simpler and safer:
#include <iostream>
#include <array>
#include <vector>
struct Data {
std::array<double,2> inputs;
std::array<double,1> target;
};
int main()
{
std::vector<Data> data = {
{ {10, 20}, {30} },
{ {40, 50}, {60} },
{ {70, 80}, {90} },
{ {100, 110}, {120} }
};
std::cout << "data[0]: inputs: " << data[0].inputs[0] << " " << data[0].inputs[1] << ", targets: " << data[0].target[0] << "\n";
}
Your original problem is that double *inputs[2] declares a 2 element array of pointers to double not a pointer to a 2 element array of doubles.
Your Data struct contains 2 fields, array of 2 double pointers, and array of 1 double pointers.
That means that initalizing it takes up to 3 double pointers, which means that in your initalization really looks like this
Data data[]{
{new double[2]{ 10, 20 }, new double[1]{ 30 }, new double[2]{ 40, 50 }}, //1st object
{new double[1]{ 60 }, new double[2]{ 70, 80 }, new double[1]{ 90 }}, //2nd object
{new double[2]{ 100, 110 }, new double[1]{ 120 }} //3rd object but 2 parameters??
};
When trying to print it in a loop, 3rd object will cause a segfault, as target field hasn't been properly initalized (when debugging with Visual Studio it's set to null, not sure about other compilers).
Your problem is here:
typedef struct {
double *inputs[2]; // this
double *target[1]; // this
} Data;
This is an array of pointers and hopefully assumed to behave live a dynamic 1D array.
Simple fix is:
struct Data {
double *inputs = nullptr;
double *target = nullptr;
} ;
However, you have a lot of heap memory allocation using new, which makes a tedious task to delete and thereby the management of your data structure really difficult.
I would strongly suggest you to use std::vector<>, which makes your task much easier and more cleaner.
#include <vector>
#include <iostream>
struct Data
{
std::vector<double> inputs; // use instead of double *inputs[2];
std::vector<double> target; // use instead of double *target[1];
//Data(const std::vector<double>& a, const std::vector<double>& b) :inputs(a), target(b){}
};
int main()
{
std::vector<Data> data = // now in your main structure array
{ { {10, 20}, {30} },
{ {40, 50}, {60} },
{ {70, 80}, {90} },
{ {100, 110},{120} }
};
// access using range based loop now
for(const Data& each_strcut: data)
std::cout << each_strcut.inputs[0] << " " << each_strcut.inputs[1]
<<"\t" << each_strcut.target[0] << std::endl;
return 0;
}

bad access error when pushing back vector

I have these two classes:
class card { //class that represents a card
int cardNumber; //the ID of the card that give it itse level and suit
std::vector<std::string> suits = { "hearts", "spades", "diamonds", "clubs" };
std::vector<std::string> levels { "Ace", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};
std::string suit;
std::string level;
public:
card(int nCardNumber) { //constructor that initiliazes all properties of the card
cardNumber = nCardNumber;
level = levels[cardNumber%13];
suit = suits[cardNumber/13];
}
void printValue() { //prints the cards level and suit
using namespace std;
cout << level << " of " << suit << endl;
}
};
and
class hand { //represents the hand a player is holding
int playerNumber;
std::vector<card> playerHand; //vector of carsa
public:
hand(int m_playerNumber) {
playerNumber = m_playerNumber;
}
void addCard(int cardNumber) { //adds a card to the hand
card cardToBeAdded(cardNumber);
cardToBeAdded.printValue();
playerHand.push_back(cardToBeAdded);
}
void printHand() {
using namespace std;
cout << "Player " << playerNumber << " has:" << endl;
for (int i = 0; i < 2; i++) {
playerHand[i].printValue();
}
}
};
and whenever I call the addCard function in hand, I get EXC_BAD_ACCESS (code=1).
I've tried some debugging by declaring two members in the playerHandVector and changing the function to rewrite those values as opposed to appending new ones to the vector, but same error.
Any help would be appreciated!
With some proper debugging, it's pretty easy to see what's going on. I've reduced your example to the very minimum that will reproduce your bug, because I don't believe it's to do with std::vector::push_back.
#include <iostream>
#include <vector>
#include <string>
class card { //class that represents a card
int cardNumber; //the ID of the card that give it itse level and suit
std::vector<std::string> suits = { "hearts", "spades", "diamonds", "clubs" };
std::vector<std::string> levels { "Ace", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};
std::string suit;
std::string level;
public:
card(int nCardNumber) { //constructor that initiliazes all properties of the card
cardNumber = nCardNumber;
std::cout << cardNumber % 13 << std::endl;
std::cout << cardNumber / 13 << std::endl;
level = levels[cardNumber%13];
suit = suits[cardNumber/13];
}
void printValue() { //prints the cards level and suit
using namespace std;
cout << level << " of " << suit << endl;
}
};
int main() {
std::vector<card> v;
for (size_t n = 0; n <= 52; ++n)
{
// Replicate "addCard" function
card c(n);
c.printValue();
v.push_back(c);
}
return 0;
}
You'll notice two things here: I've added some debugging help to the card constructor because I believed the problem was the access of the std::vector<std::string> and I'm attempting to add all 52 cards. 'lo and behold, the first 51 cards add successfully; however, trying to add the king of clubs has an error. Let's see why:
card(int nCardNumber) { // nCardNumber = 52;
cardNumber = nCardNumber; // 52
const int nCard = cardNumber % 13; // King
const int nSuit = cardNumber / 13; // 4
level = levels[nCard];
suit = suits[nSuit]; // whoops, out of bounds!
}
You can see here that you are trying to access the suits[4] which is out of bounds.
You probably have some code (which you haven't shown) which is using cardNumber as an array index, not cardNumber % 13 or similar and going out of array bounds.
Using cardnumber/13 as an array index will also fail if cardNumber is 52 or more.
Also .....
suits and levels are non-static members of card, so every instance of card will have its own copy of those vectors.
I wouldn't expect a problem to occur with every call of hand::addCard() but, if your code is creating lots of hands, adding lots of cards to them, and not cleaning up - then it will exhaust available memory quicker than you probably intend.
If you are then running into limits on available memory (that depends on you OS, available RAM, etc) then that would explain your problem.
This compiles and runs "correctly" on Visual Studio 2013 Community. Well, except that VS2013 doesn't do member initalizer lists so I had to, ugh, type those out. The only way I could get an error was to have a value outside of the obvious range of cards (>52, <0). Is that what you're doing?
Other issues: normal card decks don't have a '1' card, delete the 1 from the levels vector. After doing that, run this in main:
for (int i = 0; i < 52; ++i)
playerHand.addCard(i);
On mine it spits out all the cards, A to K, for all 4 suits, in order. However if I give it a value outside of those bounds it will give an error.
It's safer to get a value from the vector using vector.at(index) than the [] operator. The [] operator on a vector treats it just like a raw C-array, so if you don't have some kind of debugger running to catch it, it'll be undefined behavior if you feed it an inappropriate value. That means if you're lucky it crashes with no explanation. One of the advantages of a vector is that you can use the at method to summon the index, and throw an exception with a pretty clear name.
Also, if you have a function that calls for user input and it's possible to feed wrong numbers (as it is in this case), then it's a good idea to check the input to make sure it's good.
As Peter points out, using vectors in the class just to hold labels is inelegant, and wastes memory. An easy solution would be to make the variables:
static std::vector<std::string suits...
The static keyword means, among other things that you should definitely look into, that they will only be created once and persist across all instances of the class.

Where is the operator "<" used in this sample?

I tried STL sample program using "map".
http://ideone.com/LB8xvh
#include <iostream>
#include <map>
#include <cstring>
using namespace std;
class ItemName
{
char name[80];
public:
ItemName(char *s) { strcpy(name, s); }
char *get() { return name; }
};
bool operator<(ItemName a, ItemName b)
{
return strcmp(a.get(), b.get()) < 0;
}
class ItemObj
{
char str[80];
public:
ItemObj(char *s) { strcpy(str, s); }
char *get() { return str; }
};
char itemdata[][80] = {
"potion", "heal HP",
"key", "unlock a door",
"lamp", "light",
};
int main() {
map<ItemName, ItemObj> items;
for(int i=0; i<3; i++) {
items.insert(
pair<ItemName, ItemObj>(
ItemName(itemdata[i*2]),
ItemObj(itemdata[i*2+1]))); // ***** pair *****
}
map<ItemName, ItemObj>::iterator p;
char str[80];
const int kMaxLoop = 5;
int nLoop = 0;
while(nLoop < kMaxLoop) {
cout << "> ";
cin >> str;
p = items.find(str);
if(p != items.end() ) {
cout << p->second.get() << endl;
} else {
cout << "unknown item." << endl;
}
nLoop++;
}
return 0;
}
In this example, I am not quite sure where the operator "<" is used.
If I comment out the definition of the operator "<", I receive lots of errors.
std::map has a parameter to specify how to compare elements in the map (needed because a map always maintains its contents sorted in order by key). By default, that's std::less<T>.
std::less<T>, in turn, will do the comparison using operator<.
You can create a map of items for which operator< isn't defined, but to do it you need to specify the comparison function/functor explicitly.
That said: your ItemData and ItemObj are both really just doing things that std::string can already do. You could reduce most of the code above to something like this:
std::map<std::string, std::string> items{
{ "potion", "heal HP" },
{ "key", "unlock a door" },
{ "lamp", "light" }
};
It is used internally by the map to place and find entries. Otherwise, find would have to compare the key you supply it against literally every single other entry one by one and you couldn't iterate the map in key order.
Basically, maps efficiently store elements in order. To do that, they have to have some way to know what the order is, and they do that by calling operator< (unless you specify otherwise).