C++ iterating a struct - c++

Is it possible to iterate through a struct?
For example
struct team{
int player1;
int player2;
int player3;
int player4;
...
int player99;
int size = 99;
}
then run a for loop to set or access foo 1-4?
i guess pseudocode would look something like
for(int i = 0; i < size; i++){
player i = (i+1);
}
A more simplified explanation if that doesnt make sense is I Just want to be able to go through each variable without having to hard code player1 = 1; player2 =2.

One way is to put the players/elements into an array:
struct Team {
static int const size = 99;
int players[size];
};
And then:
for(int i = 0; i < size; ++i)
int player = players[i];

To answer your question as you've asked it, I believe that you can use the pre-compiler macro Pack (the exact phrase depends on your compiler) to guarantee the structure of the memory used to create an instance of your struct. And then you technically could increment a pointer to move through it... if you're mad. That would be a very poor way to do and not at all guaranteed to work on different compilers or even different days of the week. No what you want is a data structure to do the job for you; they come with a 100% cash-back guarantee!
The most basic structure to do this with is a fixed size array, e.g:
struct team
{
int players[99]; //an array
int manager;
int coach;
string teamName;
//etc etc
}
Then to access your players
team myTeam;
for(int i(0); i < 99; ++i)
{
myTeam.players[i]; //do whatever
}
The limitation of an array is that you cannot change its size once it's created.
So if you try
myTeam.players[99]; //accessing invalid memory - the array values are 0 - 98
More advanced
If you need a data structure that can change size after it's created, e.g you might want to add a few more players to your team at some point in the future. Then you can use a dynamic data structure such as the std::vector or the std::deque or std::list

I would propose to use container instead of many variables, for example you could use std::array or std::vector. This way it will be trivial to iterate, much easier to make a copy. But also it's better from design point of view: in case you decide to change the number of players it will be much easier to change the container rather than add/remove many fields

You can define pointer to member, like pointer to member function:
typedef int team::*member_t;
You can have array of pointers to all your members:
static member_t member[size];
With this approach defining member function to iterate over all members is easy:
template <class F>
void for_each(F f)
{
for (int i = 0; i < size; ++i)
f(this->*member[i]);
}
And with using of preprocessor macro - you can have in one place definition of all members, in other definition of pointer to members - so you will not make any mistake with changing their order. See full code:
struct team {
#define TEAM_MEMBERS(prefix,suffix) \
prefix player1 suffix, \
prefix player2 suffix, \
prefix player3 suffix
int TEAM_MEMBERS(,);
static const int size = 3;
typedef int team::*member_t;
static member_t member[size];
template <class F>
void for_each(F f)
{
for (int i = 0; i < size; ++i)
f(this->*member[i]);
}
};
team::member_t team::member[team::size] = {
TEAM_MEMBERS(&team::,)
};
And some test:
#include <iostream>
int main() {
team t = { 0 };
t.for_each([](int m) { std::cout << m << "\n"; }); // prints 0,0,0
int n = 0;
t.for_each([&n](int& m) { m = n++; });
t.for_each([](int m) { std::cout << m << "\n"; }); // prints 0,1,2
t.player2 = 7;
t.for_each([](int m) { std::cout << m << "\n"; }); // prints 0,7,2
}

Related

Setting-up a 2D array using std::Vector

I have already improved my array from this question in order to be created within a class, I also kind of optimized it using std::vector so it is not allocated on a heap but on a stack and thus it is faster and also I do not have to manage the memory manually.
But I was not able to create a function which would set a value to an element. I got errors like expression must have pointer-to-object type (when I try to declare my element as int cell or an array may not have element of this type (when I try to declare it as int cell[][]) and I get a segmentation error when I try to declare it like this int *cell[].
Here is my code
.hpp
#pragma once
#include <iostream>
#include <vector>
class myPlan
{
int slots;
int rows = 3;
int cell[][];
public:
myPlan(int slots);
void setCellValue(int row, int slot, int value)
};
.cpp
#include "myPlan.hpp"
myPlan::myPlan(int slots)
{
this->slots = slots;
std::vector<std::vector<int> > cell(STATUS_N);
for (int i = 0; i < STATUS_N; i++)
{
// declare the i-th row to size of column
cell[i] = std::vector<int>(slots);
}
//Print the array
for (int i = 0; i < STATUS_N; i++) {
for (int j = 0; j < cell[i].size(); j++)
{
cell[i][j] = 0;
std::cout << cell[i][j] << " ";
}
std::cout << "\n";
}
}
void myPlan::setCellValue(int row, int slot, int value)
{
cell[row][slot] = value;
}
main.cpp
#include "myPlan.hpp"
int main()
{
myPlan plan(N_PLAN);
plan.setCellValue(0,2,42);
}
Thank you very much in advance for any help
P.S. I hope that this is more optimal than this array, if there was even better optimized version, I would be glad to learn about it.
So here's what I think is the fundamental problem, it has nothing to do with arrays or vectors. You are just handling your class variable incorrectly. Here's your class
class myPlan
{
int slots;
int rows = 3;
int cell[][];
int cell[][]; is not legal C++, but we'll let that pass. The point is that you have some kind of 2D array called cell in your class.
Now here's your constructor
myPlan::myPlan(int slots)
{
this->slots = slots;
std::vector<std::vector<int> > cell(STATUS_N);
for (int i = 0; i < STATUS_N; i++)
{
// declare the i-th row to size of column
cell[i] = std::vector<int>(slots);
}
Now here you've declared a 2D vector called cell. But (and here's the point) this is not the same cell that's in your class, it a completely separate variable which just happens to have the same name. And like any variable declared inside a function it will no longer exist after the function exits.
Here's how it should be done.
class myPlan
{
int slots;
int rows = 3;
std::vector<std::vector<int> > cell;
...
myPlan::myPlan(int slots)
{
this->slots = slots;
cell.resize(STATUS_N);
for (int i = 0; i < STATUS_N; i++)
{
// declare the i-th row to size of column
cell[i] = std::vector<int>(slots);
}
See the difference? I didn't declare a new cell variable, I just resized the one that is declared in the class.
As far as I understood your problem, you need an array of arrays (a number of slots), which size is known at compile time. And you prefer it to be on the stack.
I encourage you to use std::array and forget about C-style arrays ([] - these guys). Or better learn the difference between them and make your own mind.
There is an example how to use it. The class has to be templated to provide parameters of the array sizes at compile time. It is pretty straighforward, but if you don't need it, you can just remove the template line before the class definition and replace RowNumber and SlotSize with you defines or constants known at compile time.
This solution will only work if sizes are known at compile time. If you want to provide the number of rows as myPlan constructor parameter, then you'll need to dynamically allocate memory and use std::vector or something similar.
#include <iostream>
#include <array>
template<std::size_t RowNumber, std::size_t SlotSize>
class myPlan {
std::array<std::array<int, SlotSize>, RowNumber> cells;
public:
myPlan() :
cells{} // initialize array with zeros
{
//Print the array
for (int i = 0; i < cells.size(); i++) {
for (int j = 0; j < cells[i].size(); j++)
{
std::cout << cells[i][j] << " ";
}
std::cout << "\n";
}
}
void setCellValue(int row, int slot, int value) {
cells[row][slot] = value;
}
};
#define N_PLAN 4
#define STATUS_N 3
int main()
{
myPlan<N_PLAN, STATUS_N> plan;
plan.setCellValue(0,2,42);
}

C++ How do I create a dynamic array of objects inherited from an abstract class?

My task specifically states that I have to create a random array of Squares and Triangles, that are inherited from an abstract class Figure, and then I have to print out their square area. Coming from C#, I thought I'd be off with an array of objects, but they do not exist in C++. I'm not allowed to use anything like vectors. Making a dynamic array of Figure doesn't work because apparently it never works with abstract classes. What should I do? Please, keep it simplified if possible.
Here's my current code. Very basic, but it's here just to show what I'm trying to do.
#include <iostream>
#include <stdlib.h>
using namespace std;
class Figure
{
public:
virtual double square() = 0;
};
class Square : public Figure
{
public:
double side;
double square()
{
return side * side;
}
};
class Triangle : public Figure
{
public:
double height;
double side;
double square()
{
return 0.5 * side * height;
}
};
void main()
{
int size = 20;
Figure *dyn_arr = new Figure[size]; // this doesn't work
//Also I have to fill it somehow too...
for (int i = 0; i < size; i++) cout << Figure.square(); //this doesn't work either
}
Firstly main must return int. Then you need to create an array of pointers which will show to abstract class Figure.
Figure **dyn_arr = new Figure*[size];
Then if you want to add a new object of the derived class you are adding simply like this.
dyn_arr[0] = new Triangle(); --> this will create new object which will return the address of that object, and your array is actually array of pointers.
Finnaly if you want to call the function square from any class you can do that like this.
dyn_arr[0]->square();
p.s. If you don't have at least a little experience with pointers this can be confusing.
Figure *dyn_arr = new Figure[size]; // this doesn't work
It doesn't work because we cannot create an array of Figures because of the pure virtual function. We wouldn't want to create a Figure by itself in any case. We only want to create either a Square or a Triangle and their sizes may differ. So there is no way to allocate the memory when the array is created.
You could create an array of pointers (size is known at compile time) and then iterate over that:
auto dyn_arr = new Figure*[size];
// auto in the above context becomes Figure** (pointer to a pointer)
for(int i = 0; i < size; i++)
cout << dyn_arr[i]->square();
Please keep in mind that arrays and pointers used this way is prone to errors. Far better to use std::make_unique and std::vector.
Here is one way to randomly create the objects:
Figure* go_figure()
{
std::uniform_int_distribution<int> ud{0,1};
static std::random_device rd{};
switch(ud(rd))
{
case 0: return new Square{};
case 1: return new Triangle{};
}
}
int main()
{
int size = 20;
auto dyn_arr = new Figure*[size];
for(int i = 0; i < size; i++)
dyn_arr[i] = go_figure();
for(int i = 0; i < size; i++)
cout << dyn_arr[i]->square();
for(int i = 0; i < size; i++)
delete dyn_arr[i];
delete[] dyn_arr;
}
You can create a list of generated functions to select from, to create dynamically allocated objects. Using a rng you can then randomly select from the list of generated functions to call, in order to fill out an array of unique_ptr<Figure> s.
Example using std::deque instead of std::vector :
template<typename T>
Figure* Create() { return new T(); }
std::function<Figure*(void)> createFunctions [] = {
Create<Square>
,Create<Triangle>
};
int main()
{
std::deque<std::unique_ptr<Figure>> shapes;
std::mt19937 rng;
rng.seed(std::random_device()());
std::uniform_int_distribution<std::mt19937::result_type> idxSel(0,1);
for(int i = 0; i < 20; ++i)
{
shapes.emplace_back(createFunctions[idxSel(rng)]());
}
}

Struggling to pass an array created in one function to a sort function

I am currently working on a project where we have to create an array of 1000 elements then pass it to another function to sort it. Everything I have seen online shows you how to pass it from main to another function, but not the other way around.
Please take a look at my code and help me pass Ar[1000] from Array() to ISort and ultimately main
#include <iostream>
#include <time.h>
using namespace std;
void Array()//function to make array
{
int Ar[1000];//creating array
int i = 0;//random variable to be element #
int counter = 0;// counter variable
int randnum;//variable to old random number
srand(time(NULL));//seeding rand with time
while (counter != 1000)
{
randnum = rand();
Ar[i] = randnum;
cout << Ar[i]<<endl;
counter++;
}
}
void ISort(int Ar[1000])//Iterative sort
{
int count = 0;//another counter variable
int count2 = 0;//counter variable # 3 because nested loops
int j=0;//Temp index # similar to i
int temp; //Temp variable to help switch elements
while (count != 1000)
{
if (Ar[count] < Ar[j])
{
temp = Ar[count];
Ar[count] = Ar[j];
Ar[j] = temp;
}
}
}
/*void RSort(int Ar)//Recursive sort
{
}
*/
int main()
{
Array();
ISort();
system("Pause");
return 0;
}
Ar in your Array function will be destroyed once this function finishes, you need to have a way to prevent this, one way is to pass an array by parameter instead of making it function local variable:
void Array(int* Ar, int count)//function to make array
{
I would also change Your current ISort definition to:
void ISort(int* Ar, int acount)//Iterative sort
where acount is number of elements in Ar. This is because it makes no difference whether you use void ISort(int Ar[1000]) or void ISort(int* Ar) (read here for more on this). If you want to preserve array type then you must pass it by reference using: void ISort(int (&Ar)[1000]).
Finally changes in main:
int Ar[1000];//creating array
Array(Ar, 1000);
ISort(Ar, 1000);
system("Pause");
return 0;
working code is here: http://coliru.stacked-crooked.com/a/678f581f802da85b
You also forgot to increment count inside your sorting loop.
Your array int Ar[1000] variable inside an Array() function is a local variable. Make it a global variable by moving it out of the function scope:
int Ar[1000]; //creating array
// your functions here
int main()
{
Array();
ISort(Ar);
return 0;
}
You should also modify the Array() function to accept array as parameter as pointed out in the comments below. Please note that I am omitting the array size part as it seems the number of the elements is set to 1000:
void Array(int Ar[]){
//...
};
in which case the above code would be:
int Ar[1000]; //creating array
// your functions here
int main()
{
Array(Ar);
ISort(Ar);
return 0;
}
Change the Array function declaration to:
int* Array() and make it return the array Ar. And in main get the returned value from Array function like this:
int* Ar = Array();
and pass it to the function ISort like this : ISort(Ar);.
Here is an example on SO passing an array to a function.
The easiest solution would be to change Array function a bit:
int* Array() { // change return type to be able to return array you create
int Ar[1000];
for (int i = 0; i < 1000; i++) { // much better to use for loop than while
Ar[i] = rand(); // no need to hold another variable for random number
cout << Ar[i] << endl;
}
return Ar; // return the Ar
}
int main() {
int* array = Array();
ISort(array);
}
Hope that helps. Also there are many other solutions to this but I don't know what exact restrictions your task has. If you have any questions feel free to ask.
EDIT: So I totally forgot about that C arrays are just a plain old pointers... Well then the solution would be like this:
void Array(Ar[1000]& array) { // pass array to the function with reference
for (int i = 0; i < 1000; i++) { // much better to use for loop than while
array[i] = rand(); // no need to hold another variable for random number
cout << array[i] << endl;
}
}
int main() {
int[1000] array = Array();
ISort(array);
}
Sorry for the error but using C style arrays really isn't common in C++ when you can use vectors and maps.

Initialization of user-defined array in C++ class?

I'm working on knight's tour problem, and want to define a class, but I am having trouble with initialize an array defined by user. So the user inputs from the command line argvs are the chessboard lengths mX and nY; and a starting position(x,y). So basically, how do I initialize an array that's defined by the user?
First question: In the public part, is it right to declare int ** tour?
Second question: How do I refer to the array tour in the following functions in the same class?
Third question: In main, I called K.knight to initialize an array of dimension specified by the user, but it wasn't initialized. How do I initialize an array in main using the function K.knigt(), and be able to use the array in the following function K.knightfunc()?
class Ktour{
public:
int xSize; //m
int ySize; //n
int ** tour; //array to be initialized
int solutionsCount; //tracking solutions
int position; //position count, from 0 to m * n -1
// initialize tour matrix
void knight(int M, int N) {
position = 1;
solutionsCount = 0;
xSize = M;
ySize = N;
tour = new int * [xSize];
for (int i = 0; i < xSize; i++) {
for (int j = 0; j < ySize; j++) {
tour[i][j] = 0;
std::cout << tour[i][j] << std::endl;
}
}
}
....some other functions defined in between...
....
....
};
...
// main
int main(int argc, char *argv[])
{
Ktour K;
//user inputs chessboard length mX and nY; and a starting position(x,y)
int mX = atoi(argv[1]);
int nY = atoi(argv[2]);
int x = atoi(argv[3]);
int y = atoi(argv[4]);
//initialization
K.knight(mX, nY);
//run the recursive function;
K.knightFunc(x,y);
return 0;
}
Yeah, it seems more logical to initialize in the ctor. My take on this is you are creating an array of int pointers, and have not yet allocated the ints that are being pointed to.
You have a few possibilities:
If we are to think of a common chessboard, then since the array size is known in advance, and it's not especially big, just create it in the class:
class Ktour{
...
int tour[8][8];
...
}
although some purists might say you should only "new" such arrays. If it is a much larger array, you certainly should.
A more straightforward syntax like what you're trying to do, for handling arrays of unknown size would be:
class Ktour{
...
int **tour=0;
KTour(int M, int N) {
tour = new int * [M];
for (int i=0; i<M; ++i)
tour[i] = new int [N];
};
~KTour() {
for (int i=0; i<M; ++i)
delete [] tour[i];
delete [] tour;
};
...
}
You access it quite simply, with:
std::cout << tour[i][j];
The above kind of coding is error-prone. To reduce your future strife with memory access errors, you really should use STL container classes (or Boost ones, or Qt ones when using Qt, if their size isn't too limited - but you can use STL in Qt also), since they produce an error in debug when you access out-of-bounds subscripts for your arrays, instead of, e.g. overwriting important pointers, etc. Thus, you could use something like:
class Ktour{
...
std::vector < std::vector<int> > Tour;
KTour(int M, int N) {
// tour.resize(M); // not needed.
tour.assign(M, std::vector <int> (N, 0));
};
~KTour() {
// No need to delete
};
...
}
and you access it with
std::cout << tour[i][j];
(Note: The extra lines in the code are some artifact of the <pre> and <code> tags; necessitated by not all of my indented lines being recognized as code.)

Create sequential variable names using a loop in C++

I'm trying to create variable names using a loop.
Specifically, I am using this structure:
struct card{
string rank;
string suit;
};
This is the rest of my code as it stands, and where it says "card+i" is where I need it to say "card1", or "card2", etc.
string aSuit[4] = {" Hearts"," Clubs"," Diamonds"," Spades"};
string aRank[13] = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
string aDeck[52];
int main(int argc, char *argv[])
{
int i = 0;
for (int s=0; s<4; s++) {
for (int r=0; r<13; r++) {
card card+i;
card+i.rank = aRank[r];
card+i.suit = aSuit[s];
cout << card + i.rank << card + i.suit << endl;
i++;
}
}
system("PAUSE");
return EXIT_SUCCESS;
}
Use arrays instead:
card cards[52];
int main(int argc, char *argv[])
{
int i = 0;
for (int s = 0; s<4; s++) {
for (int r = 0; r<13; r++) {
cards[i].rank = aRank[r];
cards[i].suit = aSuit[s];
cout << cards[i].rank << cards[i].suit << endl;
i++;
}
}
system("PAUSE");
return EXIT_SUCCESS;
}
You think this is the best solution, but I can assure you, it is not. Tying your logic to the names of variables is a bad, bad idea, from a logical as well as maintenance standpoibnt. What you really want is a collection which can associate one piece of data (in this case, a string) with another.
Look into a data structure like a map
This isn't possible. When you compile a C++ program, any concept of variable names completely disappears. It can't generate variable names at run time because they just don't exist.
However, there is a way to do this, of course. This is precisely what arrays are for. They give you a whole set of objects that you can index by number (i, in your case). You already have a variable named aDeck but I think you've defined it incorrectly. Did you perhaps want:
card aDeck[52];
Now you'll have a deck of 52 cards. Each card in this deck has suit and rank members. You can access each member of the array with aDeck[i]. So change the inside of your loop to:
aDeck[i].rank = aRank[r];
aDeck[i].suit = aSuit[s];
You need to use arrays for this, they allow a single variable to contain a group of items.
Then you simply use the variable name with an index, such as:
int xyzzy[5];
for (int i = 0; i < 5; i++)
xyzzy[i] = i * 7;
// gives 0, 7, 14, 21, 28
In fact, your code already has arrays representing the suits and card face values, not really that different from what you need here, so I'm not certain why you didn't make the logic-leap to using them for the cards as well. But that's basically how you'd do it.