So recently, I have been struggling with passing an array to the function (described below). My problem is that when I pass an array only the first element of the array works properly (shown with cout's). And also, object "Enemy" is a child of "Obj".
Creating an array of enemies:
const int eN = 2;
Enemy enemyArray[eN];
for (int i = 0; i <eN; i++) {
enemyArray[i].creating("abc.png", Type::ENEMY);
enemyArray[i].position = Vector2f(x, y);
enemyArray[i].loadChasePoint();
enemyArray[i].number = i + 100;
enemyArray[i].updatePosition();
x += 50; y += 50;
}
The function that includes this array:
void Obj::movement(Vector2f mVector, Obj* b, int objsNumber) {
bool collision = false;
position.x = position.x + mVector.x;
for (int i = 0; i < objsNumber; i++) {
if (!(type == Type::NONE)) {
//if (type == Type::PLAYER) { cout<<"Inside: "<< b[1].getSprite().getPosition().x << endl;} Prints "0"
if (isColliding(b[i])) collision = true;
}
}
if (collision == 1) position.x = position.x - mVector.x;
collision = false;
position.y = position.y + mVector.y;
for (int i = 0; i < objsNumber; i++) {
if (!(type == Type::NONE)) {
if (isColliding(b[i])) collision = true;
}
}
if (collision == 1) position.y = position.y - mVector.y;
}
Calling that function:
//cout <<"Outside: "<<enemyArray[1].getSprite().getPosition().x<<endl; Prints actuall position
playerArray[0].movement(mVector, enemyArray, eN);
the problem is, that you pass an array of type Enemy to a function that expects an array of type Obj. That only works if you pass a single object and if Enemy inherits from Obj. this cannot work for arrays:
sizeof(Obj) is some X. So accessing obj[1] would expect that the second object starts at address adressof(b)+X.
But since your object-array is of type Enemy that has a different size (most probably X+Y) this pointer arithmetics fails at this point since the real address of the second object would be adressof(b)+x+y.
Some variants to solve this:
make b of your movement - function a template arguement
change the b argument to a Obj*-Array and create pointer array from your enemy list before calling the function
I would prefere the first variant. And if your are going to refactor - I would suggest to get rid of the plain pointers and arrays. use std container instead and use their iterators.
Related
I implemented a mergesort algorithm but it returns the exact same array I pass as an input. The following is the code. I am suspecting the pseudocode that our professor gave us is wrong. But I am not sure. I have tried to implement is as best as I can.
int len(double *a) {
int count = 0;
while (a[count] != '\0') {
count++;
}
return count;
}
double* merge(double* b, double* c, int N) {
int i = 0;
int j = 0;
double* result = new double[N];
for(int k = 0; k < N; k++) {
if ((i < len(b)) && (j >= len(c) || b[i] <= c[j])) {
result[k] = b[i++];
} else {
result[k] = c[j++];
}
}
return result;
}
void merge_sort(double* a, int N) {
if (N >= 2) {
int mid = (N+1)/2;
double *left = new double[mid];
double *right = new double[mid];
for (int i = 0; i < mid; i++) {
left[i] = a[i];
}
for (int j = 0; j < mid; j++) {
right[j] = a[mid + j];
}
merge_sort(left, mid);
merge_sort(right, mid);
a = merge(left, right, N);
}
}
Any help would be really appreciated.
In the last line, you assign your result to the local var a, which is then lost. You need to return a, or pass the input as a reference/pointer, otherwise any changes are only to the local copy.
Arguments in the function are basically local variables, they behave like any local variable in this function, except their initial value is set by code that calls this function. a is a pointer that stores the address of first element of your double array.
As it's a local variable, you can modify it but when the function ends, it will be discarded like all other local variables of the function.
There are several ways to deal with this problem, each with their own up and downsides. The most obvious is to return final value of a when you're done sorting. You could also pass a pointer TO a pointer to this function, and then you would be able to modify the pointer outside the function:
void function(int** argument){
*argument = another_function();
}
, but that severely restricts the source of your input. It no longer could be a local array passed by address like this:
int x = 10;
int *y = &x; // if this is what you want to change
function(&y); // this works
// now x is still 10, y points to a different place in memory which can store a different value
int x[1]; // if you would like to change this array in place though...
function(x); // this is how you would call the function, but it would fail because it can't change the address that x refers to
You main issue is here:
// You pass in a pointer to the data here.
// the parameter `a` holds a pointer to the data.
void merge_sort(double* a, int N) {
if (N >= 2) {
// STUFF
// Here you write over `a` (which is fine)
// BUT: You don't pass the value back.
// So the caller never knows what the new value is.
a = merge(left, right, N);
}
}
To fix this. I think it is a mistake to allocate a new array in merge(). Rather re-use the array you have. You have already copied the data into left and right to be sorted. The merge should merge the data back into the original array a.
// Change this:
a = merge(left, right, N);
into
merge(a, left, right, N);
Now in merge() you can use a as the destination.
void merge(double* result, double* b, double* c, int N)
// No longer need to allocate space for result now.
There are a couple of other issues:
1: What do you need len() for?
int len(double *a) {
int count = 0;
while (a[count] != '\0') {
count++;
}
return count;
}
You should already know the length of all parts you should not be re-measuring it. Also this function is completely wrong (the double array is not \0 terminated).
2: The length of b and c is not obvious.
double* merge(double* b, double* c, int N) {
You get the wrong value because you call len() which is not correct.
You could calculate from N but that has issues in that you need to make sure both you merge functions use exactly the same method and that is error prone in the long run. I would personally pass the size of each array as parameters to the function.
3: You leak your intermediate arrays!
You call new to allocate storage.
double *left = new double[mid];
double *right = new double[mid];
But you don't deallocate these objects so they are leaked (for every call to new there should be a corespodning call to delete).
Overall. You can solve a cople of issues by using more C++ style techniques (rather than the C style you are using). Iterators and std::vector spring to mind.
For the heads up: I am incredibly new with cpp. Being used to PHP and JS as work languages, I find pointers incredibly confusing.
So I have this Class called Macierz. The class is supposed to hold Matrixes of float variables and ought to have a constructor accepting an 2d array in order to print them into the field.
The field is declared like this
float mx3[3][3];
And the constructor has such declaration: Macierz(float**);
With the body using an additional function:
Macierz::Macierz(float** f) {
length = 3;
populateWith(f, length);
}
void Macierz::populateWith(float** val, int length) {
for (int i = 0; i < length; i++)
for (int j = 0; j < length; j++)
mx3[i][j] = val[i][j];
}
In my main() function I want to declare the class with a created float array.
I try to do it as so, but It just won't work the way God intended:
float y[3][3] = { {1.00f, 2.00f, 3.00f}, { 4.00f, 5.00f, 6.00f }, { 7.00f, 8.00f, 9.00f } };
Macierz m5(y);
This is the base template of what I want to do. I've tried making the y variable a double pointer, a regular pointer, passing via reference and it just won't kick.
What would be the most prober way to pass this variable?
Any help will be amazing, I am really a noob in this language.
You need to remember that arrays naturally decays to pointers to their first element. But that isn't recursive.
For y in your example, the decay is to a pointer to the first element of y, which is equal to &y[0]. That is a pointer to an array, and will have the type float(*)[3], which is the type you need for your arguments:
Macierz::Macierz(float (*f)[3]) { ... }
Managed to fix this by copying the float into a pointer-to-pointer types
float y[3][3] = { {1.00f, 2.00f, 3.00f}, { 4.00f, 5.00f, 6.00f }, { 7.00f, 8.00f, 9.00f } };
float** x = 0;
x = new float*[3];
for (int i = 0; i < 3; i++) {
x[i] = new float[3];
for (int j = 0; j < 3; j++) {
x[i][j] = y[i][j];
}
}
Macierz m5(x);
In my main, I call the function compute_entropy and I give it a vector like this:
float entropy = h.compute_entropy(input_pic[0], & Symbol_table);
In Implementing the function itself (in h.cpp), I should not change the parameter it takes which is vector* prob.. how can I access the data of prob?
float compute_entropy(vector<Symbol>* prob)
{
float ent = 0;
vector<Symbol>* prob;
for (int i = 0; i < prob.size(); i++) //GIVES ERROR
{
ent += (prob.at(i).freq) * log2( 1 / (prob.at(i).freq) );
}
}
Because type of prob is Vector<Symbol> *, you actually need to dereference it first before accessing member. It looks like (*prob).at(i).freq.
*(A).B can also be written as A->B, so instead of (*prob).at(i).freq, you can write prob->at(i).freq. (With similar argument prob.size() becomes prob->size())
Doing it in cleaner wayBecause you never change the contents of your vector you can make the argument constant.
float compute_entropy(const vector<Symbol>* prob)
Now as we know pointers are evil, let's replace pointer with a reference.
float compute_entropy(const vector<Symbol> &prob)
{
float ent = 0;
for (int i = 0; i < prob.size(); i++) //GIVES ERROR
{
ent += (prob.at(i).freq) * log2( 1 / (prob.at(i).freq) );
}
}
While calling this, if you were calling with vector, drop the & from the argument, and if you were calling with a vector pointer, dereference it with a *.
vector<Symbol>* prob;
for (int i = 0; i < prob.size(); i++) //GIVES ERROR
.....
Because prob is a pointer, you need to use the -> operator
for (int i = 0; i < prob->size(); i++)
I am a beginning programmer writing a graphical game using SDL. The function that splits a tile-sheet into sections or "clips" and puts it into a array and the function that draws specific "clips" onto the screen are not working as intended.
void split_tilesheet(int width, int height, int space, Entity * ent){
std::cout << "Splitting Tileset...";
int t_width = (width / SPR_W);
int t_height = (height / SPR_H);
int numTiles = (t_width * t_height);
ent = new Entity [numTiles + 1];
if( ent == NULL){
err("!failed to alloc!");
}else{
std::cout << "allocated"<< std::endl;
}
int count = 0;
for(int i = 0; i < t_width; i++){
for(int j = 0; j < t_height; j++){
ent[count].bounds.x = i * SPR_W;
ent[count].bounds.y = j * SPR_H;
ent[count].bounds.w = SPR_W;
ent[count].bounds.h = SPR_H;
ent[count].id = ent[i].x + ( ent[i].y * t_width);
count++;
}
}
}
void draw_room(char tiledata[MAP_MAX_X][MAP_MAX_Y], Entity * ent){
SDL_Rect bounds;
for(int x = 0; x < MAP_MAX_X; x++){
for(int y = 0; y < MAP_MAX_Y; y++){
if(tiledata[x][y] == '0' || tiledata[x][y] == ' ' || tiledata[x][y] == '\n' ){
draw_img(x * SPR_W , y * SPR_H, tiles, bounds, ent[0].bounds);
}
if(tiledata[x][y] == '1'){
draw_img(x * SPR_W , y * SPR_H, tiles, bounds, ent[1].bounds);
}
}
}
}
class Entity
{
public:
SDL_Rect bounds;
SDL_Surface* sprite;
int id;
int x;
int y;
int w, h;
};
I was trying to use pointers to dynamically allocate the memory at runtime.
The program compiles, but segfaults. gdb says that the segfault is due to the draw_room() function, but I cannot figure out why. The pointer I was passing to the draw_room function was:
Entity * floor0_clips = NULL;
This didn't work either
Entity * floor0_clips;
Please help...
C++ uses pass-by-value (unless you specify pass-by-reference), which you didn't.
A variable in a function is a copy of the argument given. For example:
int func(int x)
{
x = 5;
}
int main()
{
int y = 6;
func(y);
// here, `y` is still `6`
}
Your case is fundamentally the same as this. You send floor0_clips to a function, the function updates a copy of it, leaving the original unchanged.
To use pass-by-reference instead, put the & symbol just before the variable name in the function's parameter list, i.e. in your case Entity * &ent . Do not change anything in the code which calls the function; it is the function's parameter list declaration that decides whether the value is passed by value or by reference.
NB. You appear to be allocating too many Entities anyway (why the + 1?).
First of all I am not proficient programing, so please be lenient. :)
I was curious what causes the error called "Stack overflow". I am using Visual C++ 2010 Express.
struct elem
{
BITMAP * colltile;
elem * next;
};
/* put some code here */
int collision_map (unsigned int poz_x, unsigned int poz_y)
{
elem * wsk = this->where_the_head_of_list_is;
int x,y;
x = poz_x%64; //coord x on tile (0-63px)
y = poz_y%64; //coord y on tile (0-63px)
poz_x /= 64; //preparing poz_x and poz_y to point on a tile on a grid
poz_y /= 64; //integers do not have to be floored
//for (int j=(poz_y*(this->size_x)+poz_x); j>0; j--) //normally works... but
for (int j=0; j<1000; j++) //this version is not
{
if ((!(wsk = wsk->next)) ||
((poz_x+1) > this->size_x) ||
((poz_y+1) > this->size_y))
{ //should check if there is no new pointer or just out of map
return -1;
}
}
return getpixel(wsk->colltile, x, y);
}
Why is the condition not working when j reaches the value of length of the list?
Things you can/have to do:
Adding debug output will help you find the error. Add some std::cerr << wsk << std::endl in your code and check if/when it becomes zero.
Possibly the pointer is zero at the beginning of your function at elem* wsk= .... If this is the case wsk->next will access a null pointer. You have to check if the pointer is valid.
Since you have pointer members in your class (as indicated by this->where_the_head_of_list_is) you need to implement copy constructor, assignment operator and destructor, which you might not have done. See here for an explanation.