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].
Related
In the code below, there is class Tile, and TQ, a set of Tiles, of which i use the struct tCmp_id to compare the set elements. mkTile simply returns a Tile object given an id value.
In main, i add four elements to TQ: 4 tiles, with ids of 1, 2, 4, and 5.
I also call upper_bound and lower_bound on TQ, which should give 2 and 4, respectively. However, on I running the program, I'm getting 4 and 4, respectively, as outputs.
Here's the code:
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
using namespace std;
class Tile {
public:
int id;
};
struct tCmp_id {
bool operator()(Tile a, Tile b) const {
return a.id < b.id;
}
};
set<Tile, tCmp_id> TQ;
Tile mkTile(int id){
Tile t;
t.id = id;
return t;
}
int main(){
TQ.insert(mkTile(1));
TQ.insert(mkTile(2));
TQ.insert(mkTile(4));
TQ.insert(mkTile(5));
cout << (*TQ.lower_bound(mkTile(3))).id << endl;
cout << (*TQ.upper_bound(mkTile(3))).id << endl;
}
Can somebody explain what's going on here? I've tried searching online or editing tCmp_id, but nothing's working so far. Thanks in advance
std::set::lower_bound - Returns an iterator pointing to the first element that is not less than (i.e. greater or equal to) key.
std::set::upper_bound - Returns an iterator pointing to the first element that is greater than key.
Since you use 3 as the key to search for, you'll get 4 in both cases.
For lower_bound 4 is the first value not less than 3, i.e. it's greater or equal to 3.
For upper_bound 4 is the first value greater than 3.
I know, the question is really complicated. Believe me, I am too. But I think a better programmer than me should know the solution. I have the following:
int cash[5] = {90000, 50000, 50000, 20000, 0};
int bankaccounts[3];
int dicenumberforeachplayer[3] = {6, 3, 9}; //Every indice is a player,
so dicenumberforeachplayer[0] is player one and so on
I have to add the highest cashnumber to the player, with the highest dicenumber, then the second player the second highest cash and so on. but I really don't know how. I am really confused, bc I am working on a project all day and I've come really far (i've written maybe 3000 lines of code) but I really hate to stop and confuse me with this problem for hours. Pls help me :((
I think, that I have to sort the player or sth like this and then I could use a for-loop for inserting the cash in every acc but I am really tired and I can't think right now XD
Modern C++ approach. There are no Magic numbers. Every thing is governed by the size of its respective array.
#include <algorithm>
#include <iostream>
int main()
{
int cash[5] = {90000, 50000, 50000, 20000, 0};
int bankaccounts[3] = {}; // added initializer to zero accounts
int dicenumberforeachplayer[3] = {6, 3, 9};
// iterate until we run out of prizes or players, whichever comes first
for (size_t cashcounter = 0;
cashcounter < std::min(std::size(dicenumberforeachplayer),
std::size(cash));
cashcounter++)
{
// find location in array of highest-rolling player
auto location = std::max_element(std::begin(dicenumberforeachplayer),
std::end(dicenumberforeachplayer));
// transform location into array index
auto index = std::distance(std::begin(dicenumberforeachplayer),
location);
//increase money in bank account for this player
bankaccounts[index] += cash[cashcounter];
// give winner impossibly low dice roll so they don't win again next time.
// Assumption: rolls cannot be negative. If they can, -1 might not be small enough
dicenumberforeachplayer[index] = -1;
}
// for display and test, print all accounts
for (const auto & val : bankaccounts)
{
std::cout << val << std::endl;
}
}
Use max_element to find the maximum and set the element to -1 then you can use the same max_element to get the next maximum element
int *max_player = max_element(dicenumberforeachplayer, dicenumberforeachplayer + 3);
int *max_money = max_element(cash, cash + 5);
bankaccount[(max_player - dicenumberforeachplayer)] += *max_money;
*max_player = *max_money = -1;
so I'm having an issue passing an entire array of histograms into a function in C++
the arrays are declared like this
TH1F *h_Energy[2];
h_Energy[0] = new TH1F("h1", "h1", 100, 0, 100);
h_Energy[1] = new TH1F("h2", "h2", 100, 0, 100);
And here is what I'm trying to do in the function:
void overlayhists(TH1 *hists, int numhists) {
int ymax = 0;
for (int i=0; i<numhists; i++) {
if (hist[i].GetMaximum() > ymax) {
ymax = (hist[i].GetMaximum())*1.05;
}
}
}
And I'm passing the function an array like this
overlayhists(*h_Energy, 2);
Where h_Energy is an 1D array with 2 elements. The code will run through the first histogram in the loop but as soon as it starts the second loop and tries to access hist[i].GetMaximum() on the second try it segfaults.
What gives?
This creates an array of pointers to type TH1F
TH1F *h_Energy[2]; //edited after OP changed
If you want to use this, and subsequently pass it as an argument
You must first initialize it, and then create your function prototype to accommodate:
void overlayhists(TH1F **hists, int numhists);
^^
From what you have shown above, you would call it like this: (after your initializations)
h_Energy[0] = new TH1F("h1", "h1", 100, 0, 100);
h_Energy[1] = new TH1F("h2", "h2", 100, 0, 100);
overlayhists(h_Energy, 2);
1. Passing any array to function in c++ to change the content:
Refer to this code snippet:
//calling:
int nArr[5] = {1,2,3,4,5};
Mul(nArr, 5);
Whenever you pass an array to function you actually pass the pointer to first element of the array. This is implicit to C++ and C. If you pass normal value(non array) it will be considered as pass by value though.
// Function Mul() declaration and definition
void MUl(int* nArr, size_t nArrSize){
size_t itr = 0;
for(;itr<nArrSize; itr++)
nArr[i] = 5*nArr;// here we've coded to multiply each element with 5
}
2. Passing any Ptr to function in c++ to change what pointer is pointing to:
Now let us suppose we want to copy nArr (from above code snippet) to another array, say nArrB
The best way for a beginner would be to use reference to the pointer.
You can pass reference to the pointer to your function
//so we had
int nArr[5] = {1,2,3,4,5};
int *nArrB;
Here we don't know the gonnabe size of nArrB.
to copy nArr to nArrB we have to pass nArr, address of pointer to nArrB(or reference to pointer of nArrB or pointer to pointer of nArrB) and size of array.
Here is the implementation.
//Calling
CopyNArr(nArr, &nArrB, 5);
//Function implementation
void CopyNArr(int* nArr, int* & nArrB, size_t nArrSize) {
// dymanically allocating memory size for array. Assuming 4 byte int size
nArrB = new int[nArrSize*4];
size_t itr = 0;
//Copying values
for(;itr<nArrSize; itr++)
nArrB[i] = nArr[i];
}
//After copy nArrB is pointing to first element of 5 element array.
I hope it helped. Write for any further clarification.
You have an array of size 2, but you've created only one element. And that one with a wrong index. Array indexing starts with 0.
The elements should be at h_histogram[0] and h_histogram[1].
I am sorry if this answer is completely irrelevant but
I am tempted to post it. These is an experiment I have
done after seeing your question.
#include<iostream>
using namespace std;
main()
{
int e[2]={0,1};
int *p[2];
int i;
/*
Printing the array e content using one pointer
from an array of pointers. Here I am not using p[2]
at all.
*/
p[1]=e;
cout<<"Elements of e are : \n";
for(i=0;i<2;i++)
{
cout<<*(p[1]+i)<<endl;
/*
In the above line both *((*p)+i) and *(p+i)
won't serve the purpose of printing the array values.
*/
}
/*Printing the array e content using pointer to array*/
cout<<"Elements of e are : \n";
for(i=0;i<2;i++)
{
cout<<*(e+i)<<endl;
}
/*Note that pointer to array is legal but array TO pointer
(don't confuse with array OF pointers) is not.*/
}
Hope this will refresh your understanding.
I'm doing a little graphics programming and I have a two dimentional array (that varies in size during program execution) that I store using openGL.
So when I go to access it, all I get is a void pointer back.
To make the logic easier, I want the compiler to pretend that it is, and use it as, a 2D array (because arr[i][j] is more concise and less error prone than ptr[i * y + j]).
This clever method of casting I found works fine in GCC (on the linux machines at uni):
Vertex (&vertices)[tess][tess] = *reinterpret_cast<Vertex (*)[tess][tess]>(
glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY)
);
Which basically casts the block of memory pointer openGL gave me to a tess X tess 2D array, and creates a reference of that type to point at it.
This allows me to access the memory like vertices[i][j].
Vertex is just a typedefed struct containing floats
However, at home on my Windows machine, VS'12 has a hissy fit, complaining that it requires the integers where tess is written to be constant (specifically; error C2057: expected constant expression).
I have no idea why.
Now, I understand that VS doesn't support VLA's, but I am not creating an array here, I'm creating a reference to something that I don't know the size of 'till runtime.
So it shouldn't care if the size changes between function calls, right? Why is this not allowed?
Not to be deterred I tried using std::array
std::array<std::array<Vertex, tess>, tess>& vertices;
And apart from the obvious references must be initialized this test didn't help me because it still complained about expression must have a constant value (specifically; error C2975: '_Size' : invalid template argument for 'std::array', expected compile-time constant expression)
I am at a loss at what to try here, I was so proud of the reinterpret_cast and how simple it made things and was sure I wasn't using a method that was contravening the standard.
I don't want to create a std::vector from the pointer then copy the data from that dynamic array back into the pointer location when I'm finished; that just seems so inefficient when the memory block is already just sitting there!
There's no way to create a vector around a pre-existing block of memory, is there? ..no that sounds silly.
I want to see if this can be done without giving up and just using it as Vertex*; Ideas?
Can someone enlighten me as to why it isn't working in VS?
Is there something I can do to get it working (extensions/updates to VS)?
Does VS'13 add support for this?
I am also getting the error C2087: 'vertices' : missing subscript that I can't explain.
As well as these other errors that seem to show VS desperately wants tess to be constant:
error C2466: cannot allocate an array of constant size 0
error C2540: non-constant expression as array bound
error C2440: 'initializing' : cannot convert from 'Vertex [1][1]' to 'Vertex (&)[][1]'
Well that was fun; I implemented a class to handle exactly what I wanted.
It's not as typesafe as I'd like, but I learned a lot doing it
Much like how I felt implementing should-be-a-part-of-the-specification, syntactic-sugar-esque functionality for javascript before I discovered jQuery.
Basically, instead of being able to do this.
int (&array)[x][y] = *reinterpret_cast<int (*)[x][y]>(pointer);
You will have to do this
MDAI<int, 2> array = MDAI<int, 2>(pointer, x, y);
But other than that it works flawlessly! :D
I initially wrote just a specialised TwoDArray class but found I actually had some 3D arrays too.
So instead of implementing a 3D version (that returned TwoDArray when you drilled down) I made something more generic and can help with arrays of as many dimensions as you'd like.
#include <Windows.h>
#include <iostream>
/*MultiDimensional Array Interpretation
has the compiler use a flat pointer reference as if it were a faceted array
C++11/GCC VLA-supporting equivalent:
int (&array)[x][y] = *reinterpret_cast<int (*)[x][y]>(pointer);
using MDAI, <C++11 and MSVS compatible:
MDAI<int, 2> array = MDAI<int, 2>(pointer, x, y);
*/
template<class Type, unsigned int dimension>
class MDAI {
private:
Type* array;
//+1 to guard against zero-length-array
unsigned int bounds[dimension + 1];
public:
//unfortunately I can't use `unsigned int &(dimensions)[dimension]` to make it safe
//because of how operator[]() tries to construct its return value
/*constructor*/
MDAI(Type* array, unsigned int* bounds)
: array(array)
{
std::copy(bounds, bounds + dimension, this->bounds);
}
/*programmer usable constructor for typing of the dimensions, instead of having to declare an array*/
MDAI(Type* array, ...)
: array(array)
{
va_list arguments;
va_start(arguments, array);
for (int index = 0; index < dimension; ++index)
bounds[index] = va_arg(arguments, unsigned int);
va_end(arguments);
}
/*drills down one level into the multi dimensional array*/
MDAI<Type, dimension - 1> operator[](unsigned index) {
if (dimension < 1) {
std::cerr << "MDAI is not an array.\n";
throw 1;
}
if (index < 0 || index >= bounds[0]) {
std::cerr << "Index out of bounds.\n";
throw 1;
}
//figure out how many addresses to jump
for (unsigned int index2 = 1; index2 < dimension; ++index2)
index *= bounds[index2];
return MDAI<Type, dimension - 1>(array + index, bounds + 1);
}
/*'dereferences' the array to get a reference to the stored value*/
Type& operator*() {
if (dimension > 0) {
std::cerr << "MDAI is an array.\n";
throw 1;
}
return *array;
}
/*allows the compiler to automagically 'convert' the MDAI into whatever the user thinks it is*/
operator Type&() {
return **this;
}
/*makes assignment work automagically too!*/
MDAI<Type, dimension>& MDAI<Type, dimension>::operator=(Type value) {
**this = value;
return *this;
}
};
Testing a three-dimensional array of bounds 2-4-3:
void main(unsigned int argC, char** argV) {
using namespace std;
int array[2][4][3] = {
{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{10, 11, 12}
},
{
{13, 14, 15},
{16, 17, 18},
{19, 20, 21},
{22, 23, 24}
}
};
//cast array to pointer, then interpret
MDAI<int, 3> mdai((int*)array, 2, 4, 3);
//testing correct memory access
cout << 15 << ' ' << mdai[1][0][2] << endl;
//testing modifcations using mdai are in array
mdai[0][2][1] = -1;
cout << array[0][2][1] << ' ' << mdai[0][2][1] << endl;
//testing modifications in array show up in mdai
array[1][3][2] = -23;
cout << -23 << ' ' << mdai[1][3][2] << endl;
//testing automatic type casting
cout << -15.0 << ' ' << mdai[0][0][1] * -7.5 << endl;
}
It's as seamless as it would have been had I left it as an array reference.
For compile-time safety I wanted to have redeclare operator*() as, specifically;
Type& MDAI<Type, 0>::operator*()
so you could only call it on a <X, 0>
But I couldn't figure it out.
Similarly get operator[]() to only appear for dimensions greater than 0
Oh well, runtime checking will have to be good enough
OK, I am trying to get a sub array from an existing array and I'm just not sure how to do it. In my example I have a very large array, but I want to create an array from the last 5 elements of the array.
An example of what I am talking about would be:
int array1 = {1,2,3,...99,100};
int array2[5] = array1+95;
I know this isn't correct, but I am having some trouble getting it right. I want to get the elements 96 through 100 in array1 and put them into array2 but I don't want to copy the arrays. I just want array2 to start at the 96 element such that array1[96] and array2[0] would be pointing to the same location.
for this:
"such that array1[96] and array2[0] would be pointing to the same location."
you can do:
int *arr2 = arr1 + 96;
assert(arr2[0] == arr1[96] == 97);
A reference hack from a C programmer willing to subvert the type system to get what works:
int (&array2)[5] = (int (&)[5])(*(array1 + 5));
Now array2 will be an array for all intents and purposes, and will be a sub-array of array1, and will even be passable to that famous C++ array_size template function. Though the best way to handle this hackery is to hide it with more hackery!
#define make_sub_array(type, arr, off, len) (type (&)[len])(*(arr + off));
int (&array2)[5] = make_sub_array(int, array1, 5, 5);
Nice. Terrible by some standards, but the end result a) looks pretty neat, b) does exactly what you want, c) is functionally identical to an actual array, and d) will also have the added bonus (or mis-feature) of being an identical reference to the original, so the two change together.
UPDATE: If you prefer, a templated version (sort of):
template <typename T, size_t M>
T (&_make_sub_array(T (&orig)[M], size_t o))[]
{
return (T (&)[])(*(orig + o));
}
#define make_sub_array(type, array, n, o) (type (&)[n])_make_sub_array(array, o)
int (&array2)[5] = make_sub_array(int, array1, 5, 5);
We still have to pass the type. Since one of our arguments must be used as part the cast, we cannot cleanly (IMHO) avoid the macro. We could do this:
template <typename T, size_t M, size_t N>
T (&make_sub_array(T (&orig)[M], size_t o))[N]
{
return (T (&)[N])(*(orig + o));
}
int (&array2)[5] = make_sub_array<int, 15, 5>(array1, 5);
But the goal here is to make the calling code as clean as possible, and that call is a bit hairy. The pure-macro version probably has the least overhead and is probably the cleanest to implement in this case.
You can use boost::iterator_range to represent "slices" of arrays/containers:
#include <iostream>
#include <boost/range.hpp>
int main()
{
int array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// Create a "proxy" of array[5..7]
// The range implements the concept of a random sequence containter
boost::iterator_range<int*> subarray(&array[5], &array[7]+1);
// Output: 3 elements: 5 6 7
std::cout << subarray.size() << " elements: "
<< subarray[0] << " "
<< subarray[1] << " "
<< subarray[2] << "\n";
}
Note that the iterator range "knows" about the size of the sub-array. It will even do bounds checking for you. You cannot get that functionality from a simple pointer.
The usefulness of Boost.Range will become more apparent once you learn about STL containers and iterators.
If you're into linear algebra, Boost.uBlas supports ranges and slices for its matrices and vectors.
For a completely different approach you could do something like.
vector<int> v0(array1 + 95, array1 + 100);
or
vector<int> v1(array1, array1 + 100);
vector<int> v2(v1.begin() + 95, v1.end());
This would make a real copy of the elements of your vector.
In C++ you can use an int pointer as an int array, so getting the array2 to start at item 96 in array1 is easy, but there isn't any way to give array2 a size limit, so you can do this
int array2[] = &array1[96];
or this
int *array2 = &array1[96];
but NOT this
int array2[5] = &array1[96]; // this doesn't work.
On the other hand, C++ doesn't enforce array size limits anyway, so the only real loss is that you can't use sizeof to get the number of elements in array2.
note: &array1[96] is the same thing as array+96
edit: correction - int array[] = &array[96] isn't valid, you can only use [] as a synonym for * when declaring a function parameter list.
so this is allowed
extern int foo(int array2[]);
foo (&array1[96]);
int array1[] = {1,2,3,...99,100};
int *array2 = &array1[96];
int arr[] = { 1, 2, 3, 4, 5};
int arr1[2];
copy(arr + 3, arr + 5, arr1);
for(int i = 0; i < 2; i++)
cout << arr1[i] << endl;
The code is not safe if the boundaries are not handled properly.
You said you don't want to copy the array, but get a pointer to the last five elements. You almost had it:
int array1[] = {1,2,3,...99,100};
int* array2 = &array1[95];