collection of pointers pointing to objects, clarification - c++

I am quite new to c++ so I have a lot of problems with pointers, although I understand the concept. The problem is that I am making a vector of pointers in my main:
main/Aquarium.cpp:
using namespace std;
#include "EntityControl.h"
#include <Windows.h>
int main() {
EntityControl entity;
vector<Fish*> fishVector;
Fish q;
cout << "fish q = " << &q << endl;
fishVector.push_back(&q);
entity.movementController(&fishVector);
cout << &fishVector << endl;
system("pause");
return 0;
}
As you can see I add the location where you can find the fish to the fishVector, I then want to do something with the object in my EntityControl class. But I don't know how to do this, I tried getting it with a for loop but when trying to cout the result, the location is different than the fish in main.cpp.
EntityControl.cpp
#include "EntityControl.h"
void EntityControl::movementController(std::vector<Fish*> * fishInputVector)
{
unsigned int x = rand() % xContainer;
unsigned int y = rand() % yContainer;
unsigned int z = rand() % zContainer;
//i.changePosition(x, y, z);
}
EntityControl::~EntityControl()
{
}
There were a few posts of this on stackoverflow, but I didn't understand the answers. I thought I needed some extra help. So if you can explain it as easily as you can then I would be very grateful.
problem clarification: adding the memory location of a Fish object to a vector (or any collection that suffices) in main then receiving the memory location and working with the object that the memory location points to in EntityControl.cpp
extra questions:
I thought I needed a pointer to change the actual variable value in a class but,
void Fish::changePosition(int addX, int addY, int addZ)
{
xLocation = addX;
yLocation = addY;
zLocation = addZ;
//std::cout <<"VALUE ="<< getX();
}
seems to work fine, could you explain this? (x,y,z locations are private global variables in the Fish class)
If I make a pointer, should I delete the object/variable that it's
pointing to? does it stay in the memory ?
Are there any good resources I can read that might help me?
last note
If anyone can help me, thank you very much. This problem has been driving me crazy for hours.

Since the argument to movementController is a pointer, you need to indirect through it to access the vector. And since the elements of the vector are pointers, you need to indirect through them. So the code in movementController could be something like:
void EntityControl::movementController(std::vector<Fish*> * fishInputVector)
{
for (auto fish_ptr : *fishInputVector) {
unsigned int x = rand() % xContainer;
unsigned int y = rand() % yContainer;
unsigned int z = rand() % zContainer;
fish_ptr->changePosition(x, y, z);
}
}

I'm not 100% sure that I understand your question, but you seem to misunderstand pointers.
I believe you are attempting to do what's called "dereferencing". That's an operation which allows you to call methods on objects that pointers refer to. Your method should read as follows:
void EntityControl::movementController(std::vector<Fish*> * fishInputVector)
{
for(int i = 0; i < fishInputVector->size(); i++)
{
unsigned int x = rand() % xContainer;
unsigned int y = rand() % yContainer;
unsigned int z = rand() % zContainer;
fishInputVector->at(i)->changePosition(x,y,z);
}
}
I've changed two things here: I am referencing the ith element of the fishInputVector, which is a pointer. Next, I am using the dereference operator, ->, which allows you to access functions/variables on the variable that the pointer is pointing to.

Related

In C++ is it possible to modify many struct objects simultaneously using pointer magic?

Apologies, this may be a silly question and possibly very basic.
I am using a library that has a Rectangle struct as follows:
struct Rectangle {
int x;
int y;
int width;
int height;
}
I have many of these rectangles in a std::vector<Rectangle> which will always have the same x value as each other (but all the other variables can be different).
Is there a way for me to use pointer magic and create a variable cur_x and have the x of all objects in std::vector<Rectangle> change their value to whatever I set cur_x to?
The struct is provided by the library, so I can't modify it and I'm trying to avoid iterating over all the elements of std::vector<Rectangle> to change their x values. Creating my own custom struct is also not an option.
It doesn't sound like it with the constraints you've layed out. The only thing I could think of (but would still be dangerous and not a good idea IMO) would be if you could somehow enforce that all the x variables were contiguous in memory and then you could set them all at once with some memory setting trickery. But given that you can't modify the Rectangle struct I don't see how this is possible.
Your situation boils down to the fact that you need to set memory in multiple locations, the only way to do that is to multiple sets (and is likely best served with a loop)
If the X value is the same across all of your elements in the vector, and it is going to stay that way, the best idea I can think of would be to typedef another copy of the Rectangle struct and change int x to be int* x, something like this
//Somewhere global-ish
typedef struct {
int* x;
int y, width, height;
} rectangle;
int cur_X = 10;
for (int i=0; i < rectangleVector.size(); i++){
rectangleVector[i].x = &cur_x;
}
std::cout << *rectangleVector[0].x << std::endl;
From what I understood after reading other comments, first, you need to change all of them at once, and second, you can't use pointers. So I suggest to modify the Rectange in a different way.
struct Rectangle {
static int x;
int y;
int width;
int height;
};
The static keyword will ensure that only one memory space is allocated for all Rectangle Objects, so changing it once would set all the objects to the same value. Also since the member x, is still an int, All the functions would work the same way even after overloading. (Make sure that no function is creating temporary copies of Rectangle or setting x to a temporary value).
To create multiple groups of Rectangles each having their own x, you can use references. References will ensure that all the Rectangle objects in the std::vector<Rectangle> point to one memory location, while allowing different memory locations between two different vectors.
#include <iostream>
#include <vector>
struct Rectangle
{
int &x;
int y;
int width;
int height;
Rectangle(int &_x):x(_x){}
};
int main()
{
int cur_1 = 10;
int cur_2 = 20;
std::vector<Rectangle> Group_1(100, Rectangle(cur_1));
std::vector<Rectangle> Group_2(200, Rectangle(cur_2));
std::cout << Group_1[0].x << " " << Group_1[50].x << "\n";
std::cout << Group_2[0].x << " " << Group_2[50].x << "\n";
Group_1[0].x = 12;
Group_2[0].x = 14;
std::cout << Group_1[0].x << " " << Group_1[50].x << "\n";
std::cout << Group_2[0].x << " " << Group_2[50].x << "\n";
}
The output:
10 10
20 20
12 12
14 14
So if you change x of any element of Group_1 or cur_1, all the members of Group_1 will have their x changed, however at the same time you can have a same property for Group_2 while keeping the different values than Group_1.

stack around array variable corrupted

i am trying to pass my array through my assign and draw functions. the assign function only exists to take the wins array and assign a value of 0 for all of the elements in the array. my draw function fills the array with random numbers 1-100 with 20 numbers in the array. when i try to compile i end up with a runtime error stating that the stack around my variable (array) wins is corrupted. where should i go from here?
#include<iostream>
#include <ctime>
using std::cout; using std::cin; using std::endl;
void draw(int a[]);
void assign(int a[]);
int sizeofarray = 20;
int main() {
int wins[20] = {};
assign(wins);
cout << "compiled!" << endl;
}
void assign(int a[20]) {
a[20] = {};
draw(a);
}
void draw(int a[])
{
srand(time(nullptr));
int rannum = (1 + rand() % 100);
for (int i = 0; i < 20; i++) {
a[i] = 1 + rand() % 100;
}
}
When you get an error with information as helpful as this, you should immediately be thinking "I have a buffer overflow". Then go looking for it.
Sure enough, here it is:
void assign(int a[20]) {
a[20] = {}; // <--- BOOM!
draw(a);
}
Your array can only store 20 elements. When you store something at the 21st element, you have undefined behavior.
Just adding some more information here. It's possible that you thought the offending line would zero-initialize the entire array (like it does when defining the variable). However, outside of an array definition, this is not the case. a[20] = {} is an assignment.
If you wish to zero the array, use std::fill as follows:
std::fill(a, a+20, 0);
I should point out, however, that there's no point zeroing the array in the context of your code as written. It's already zeroed on entry, and the draw function initializes every element anyway.

Pointer to std::vector of structs

struct Struct_t {
int Value1;
int Value2;
};
vector<Struct_t> Struct;
Struct.resize(10, Struct_t());
for (int i = 0; i < 10; ++i)
{
Struct[i].Value1 = (i + 10) * 3;
Struct[i].Value2 = (i + 5) * 2;
}
How can I create a pointer to Struct[i]?
What I want to do essentially is something like this, but I'm sure this can be done better:
int value = 6;
Struct_t temp = Struct[value], *s;
s = &temp;
s->Value1 = 42;
s->Value2 = 6;
Main goal is, that I can easily create a pointer to Struct[n] with 1 line/function.
So far, the provided answers are missing the elephant in the room. You could create a pointer to a vector element like so:
(Fault-prone) Code Listing
#include <iostream>
#include <vector>
struct Struct_t {
int Value1;
int Value2;
};
int main(void)
{
std::vector<Struct_t> sVec;
sVec.resize(10, Struct_t());
int count = 0;
for (std::vector<Struct_t>::iterator vIt = sVec.begin(); vIt != sVec.end(); ++vIt)
{
vIt->Value1 = (count + 10) * 3;
vIt->Value2 = (count + 5) * 2;
count++;
}
Struct_t* pStruct = &sVec[5];
std::cout << "sVec[5] = (" << pStruct->Value1 << "," << pStruct->Value2
<< ")" << std::endl;
return 0;
}
Sample Output
sVec[5] = (45,20)
However, vector is not an abstract type you want to use if you will be generating pointers to individual elements of the vector/"array". When the vector needs to be re-sized (shrink or grow), the iterators are invalidated, so your pointers will point to now-freed memory, crashing your program. If you want to have raw pointers directly to vector elements, you want to first:
Use a list rather than a vector.
Possibly use managed pointers to handle reference counts.
Finally, when dealing with template classes like vector, list, hash_table, etc, you should try to get used to using the iterator example I used above, as you don't have to worry about checking for exceptions when using an invalid index (the overloaded [] operators can throw exceptions, unless you replace them with the .at() member function instead for element access).
For a std::vector, &v[i], gives you a pointer to the i'th element. Your sample code becomes:
int value = 6;
Struct_t* s = &Struct[value];
s->Value1 = 42;
s->Value2 = 6;
So the one-liner is Struct_t* s = &Struct[value];
There is nothing wrong with doing this, but like most aspects of C++, you need to understand what you are doing. The above code is perfectly valid and guaranteed by the standard. (Also note that the code in this answer avoids an error in the original code where s was a pointer to a temporary copy and no changes were made to the contents of the Struct vector.)
Yes, resizing Struct will invalidate any pointers made before the resize, and yes, using iterators is often a better technique. But this is a correct and reasonable answer to the original question.

Assigning a 2D array (of pointers) to a variable in an object for access in C++?

I'm sorry if I didn't pick a descriptive or concise name. A lot of questions sound similar, but I haven't been able to find what I'm looking for. What I want to do is store a 2D array of pointers somewhere and assign a variable in some object to that array to be able to access it.
Here's some example code that has the same compile error I'm getting with a bigger project.
#include <iostream>
using namespace std;
struct X{
float n, * b[8][8];
X(){
n = 1;
b[1][5] = &n;
cout << *(b[1][5]) << endl;
}
void Set(float * c[8][8]){
b = c;
cout << *(b[1][5]) << endl;
}
};
main(){
float m, * a[8][8];
m = 2;
a[1][5] = &m;
X obj;
obj.Set(a);
}
What I want to happen in this code is that an X object starts with its own 2D array, whose value pointed to by b[1][5] should be printed as "1". Then the main method's 2D array, a, is passed to the object's Set() method and assigned to its array variable. The value pointed to by b[1][5] should then be printed as "2".
However, I can't figure out what type the Set() parameter, c, should be. I get
error: incompatible types in assignment of ‘float* (*)[8]’ to ‘float* [8][8]’
when I try to compile. As for why I want to do this, I'm trying to use an array of pointers to objects, not floats, but it's the same error.
Try this:
#include <iostream>
using namespace std;
struct X{
float n;
float* (*b)[8];
X(){
n = 1;
b = new float*[8][8];
b[1][5] = &n;
cout << *(b[1][5]) << endl;
}
void Set(float * c[8][8]){
delete[] b;
b = c;
cout << *(b[1][5]) << endl;
}
};
main(){
float m, * a[8][8];
m = 2;
a[1][5] = &m;
X obj;
obj.Set(a);
}
Here, X stores a pointer to a 1D array, which we are treating as a pointer to the first element of a 2D array - i.e. as just a 2D array.
In X's constructor, X allocates its own array with new and sets its pointer to point to that. When calling Set(), X deletes its own array, and sets its pointer to point to the array provided by the caller.
The only thing to watch out for is, if you call Set() again, that array will in turn be deleted (which will blow up if that array is a stack array, like in this case). So, it might be advisable to separate the line that does delete[] b into its own member function, and call it only when necessary.
Your problem with set is that you need to copy the array contents - just doing b=c can't do what you want.
void Set(float * c[8][8]){
for(unsigned int i=0; i<8; ++i) {
for(unsigned int j=0; j<8; ++j) {
b[i][j] = c[i][j];
}
}
cout << *(b[1][5]) << endl;
}
There are several bugs I think..
Firstly, in Set() function you have assigned an array name. But array name should not be used as a variable. You can solve this by making 2D array of pointer b as a pointer to 1D array of pointer like float * (*b)[8]...
Secondly, when you send the 2D array of pointer as argument of Set() function it is decaying into a pointer to 1D array of pointer i.e something like this float *(*a)[8]. so you have to make the formal argument of Set() function a pointer to 1D array of pointers like void Set(float * (*c)[8])...
And finally there is a thing your float variable m inside main is a local to main , so when control pass to Set() function I think the compiler cant find the value(may be deallocated) in the m...so it outputs undefined or give run time error..you can solve this by making m a static version. i.e by declaring static float m...
In total make your code like following :
#include <iostream>
using namespace std;
struct X{
float n, *(*b)[8];
X(){
n = 1;
b[1][5] = &n;
cout << *(b[1][5]) << endl;
}
void Set(float * (*c)[8]){
b = c;
cout << *(b[1][5]) << endl;
}
};
main(){
float * a[8][8];
static float m;
m = 2;
a[1][5] = &m;
X obj;
obj.Set(a);
}
This will output correctly :)

3D array C++ using int [] operator

I'm new to C/C++ and I've been cracking my head but still got no idea how to make an "structure" like this
It's supposed to be a 3D dynamic array using pointers.
I started like this, but got stuck there
int x=5,y=4,z=3;
int ***sec=new int **[x];
It would be enough to know how to make it for a static size of y and z;
Please, I'd appreciate that you help me.
Thanks in advance.
To create dynamically 3D array of integers, it's better you understand 1D and 2D array first.
1D array: You can do this very easily by
const int MAX_SIZE=128;
int *arr1D = new int[MAX_SIZE];
Here, we are creating an int-pointer which will point to a chunk of memory where integers can be stored.
2D array: You may use the solution of above 1D array to create a 2D array. First, create a pointer which should point to a memory block where only other integer pointers are held which ultimately point to actual data. Since our first pointer points to an array of pointers so this will be called as pointer-to-pointer (double pointer).
const int HEIGHT=20;
const int WIDTH=20;
int **arr2D = new int*[WIDTH]; //create an array of int pointers (int*), that will point to
//data as described in 1D array.
for(int i = 0;i < WIDTH; i++){
arr2D[i] = new int[HEIGHT];
}
3D Array: This is what you want to do. Here you may try both the scheme used in above two cases. Apply the same logic as 2D array. Diagram in question explains all. The first array will be pointer-to-pointer-to-pointer (int*** - since it points to double pointers). The solution is as below:
const int X=20;
const int Y=20;
const int z=20;
int ***arr3D = new int**[X];
for(int i =0; i<X; i++){
arr3D[i] = new int*[Y];
for(int j =0; j<Y; j++){
arr3D[i][j] = new int[Z];
for(int k = 0; k<Z;k++){
arr3D[i][j][k] = 0;
}
}
}
// one-liner
typedef std::vector<std::vector<std::vector<int> > > ThreeDimensions;
// expanded
typedef std::vector<int> OneDimension;
typedef std::vector<OneDimension> TwoDimensions;
typedef std::vector<TwoDimension> ThreeDimensions;
(this is tagged c++, after all)
EDIT in response to Joe's question
hello again Joe =) sure. here's the example:
#include <vector>
#include <iostream>
int main(int argc, char* const argv[]) {
/* one-liner */
typedef std::vector<std::vector<std::vector<int> > >ThreeDimensions;
/* expanded */
typedef std::vector<int>OneDimension;
typedef std::vector<OneDimension>TwoDimensions;
typedef std::vector<TwoDimensions>ThreeDimensions;
/*
create 3 * 10 * 25 array filled with '12'
*/
const size_t NElements1(25);
const size_t NElements2(10);
const size_t NElements3(3);
const int InitialValueForAllEntries(12);
ThreeDimensions three_dim(NElements3, TwoDimensions(NElements2, OneDimension(NElements1, InitialValueForAllEntries)));
/* the easiest way to assign a value is to use the subscript operator */
three_dim[0][0][0] = 11;
/* now read the value: */
std::cout << "It should be 11: " << three_dim[0][0][0] << "\n";
/* every other value should be 12: */
std::cout << "It should be 12: " << three_dim[0][1][0] << "\n";
/* get a reference to a 2d vector: */
TwoDimensions& two_dim(three_dim[1]);
/* assignment */
two_dim[2][4] = -1;
/* read it: */
std::cout << "It should be -1: " << two_dim[2][4] << "\n";
/* get a reference to a 1d vector: */
OneDimension& one_dim(two_dim[2]);
/* read it (this is two_dim[2][4], aka three_dim[1][2][4]): */
std::cout << "It should be -1: " << one_dim[4] << "\n";
/* you can also use at(size_t): */
std::cout << "It should be 12: " << one_dim.at(5) << "\n";
return 0;
}
You can try:
for(int i=0;i<x;i++) {
sec[i] = new int *[y];
for(int j=0;j<y;j++) {
sec[i][j] = new int [z];
}
}
And once you are done using this memory you can deallocate it as:
for(int i=0;i<x;i++) {
for(int j=0;j<y;j++) {
delete [] sec[i][j];
}
delete [] sec[i];
}
delete [] sec;
Comprehensive answers.
If you are really writing this in C++ (not rough C) I think you should take another look at this complicated data structure. IMO redesign while keeping in mind what you are trying to do would be better.
What you're trying to do is not idiomatic in C++. Of course, you can use a int***pointer for this, but this is strongly discouraged. In C++ we have better ways to get there.
vector<vector<vector<int> > > foo (5,vector<vector<int> >(4, vector<int>(3)));
This will result in something with the memory layout similar to what you asked for. It supports dynamic resizing and inner vectors to have different sizes just like in your picture. In addition, you don't have to worry about manual allocation / deletion of any of it. Also, the vectors know their size so you don't have to remember it somewhere.
But if you just want a "rectangular" 3D array where all the elements are consecutivly stored in the same memory block, you could use a boost::multiarray.
OK let us take your beginnings
int ***sec = new int**[x];
sec is now an array of int**s of length x, so now I am just going to focus on making the zeroeth element be what you want
sec[0] = new int*[y];
Now sec[0] points to array of int*s of length y, now just need to get the last bit of the tree done, so
sec[0][0] = new int[z];
And finally to get it to the form in your diagram
sec[0][0][z-1] = 0;
This does seem a little like a homework question, make sure you actually understand the answer and why it works.
If it's the actual arrays you'r having problems with look here: Declaring a pointer to multidimensional array and allocating the array
Not sure exactly what you want but you might want to read up on about linked lists.