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?).
Related
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.
I would like to allocate memory to store/manipulate data using a triple pointer. Given that I have to allocate the data at multiple points in my code, I implemented a function to do it. In the code below I give the implementation of this function and a simple main method that illustrates how I use this function in my code.
The code compile without error but when I run the program it crushes. I would appreciate your help to fix this problem.
EDIT: it crushes in the function AllocateMemory at the line
*data[i][j] = new double[x];
for i = 0 and j =1
Thank you.
int main()
{
int x = 2;
int y = 2;
int z = 2;
double*** data;//
AllocateMemory(&data, x, y, z);
//play with data
FreeMemory(data, x, y, z);
return 0;
}
void AllocateMemory(double**** data, int x, int y, int z)
{
*data = new double**[z];
for(int i = 0; i < z; i++)
{
*data[i] = new double*[y];
for(int j = 0; j < y; j++)
{
*data[i][j] = new double[x];
}
}
}
void FreeMemory(double*** data, int x, int y, int z)
{
for(int i = 0; i < z; i++)
{
for(int j = 0; j < y; j++)
{
delete [] data[i][j];
data[i][j] = NULL;
}
delete [] data[i];
data[i] = NULL;
}
delete [] data;
data = NULL;
}
Remember that array subscription has a higher precedence than dereference operator. Here:
*data[i] = new double*[y];
You're subscripting data and then dereferencing that pointer. data argument of AllocateMemory is not a pointer to an array, but instead to a single variable which is data in main. Therefore data[1] was never initialized and you get undefined behaviour. Given the context, you probably intended it the other way round:
(*data)[i] = new double*[y];
You have the same bug on the line *data[i][j] = new double[x];.
You could have avoided this either by using a reference parameter or - as I would recommend - by returning the pointer to the newly allocated array of pointers instead of passing it as an argument.
I have a pointer to a 3-dimensional array, like this:
char ***_cube3d
And I am initialising it like this:
_cube3d = (char ***)malloc(size * (sizeof(char**)));
for (int i = 0; i< size; i++) {
_cube3d[i] = (char **)malloc(size * sizeof(char*));
for (int j = 0; j<size; j++) {
_cube3d[i][j] = (char *)malloc(size * sizeof(char));
}
}
Note that the array is of dynamic size, and can contain thousands of elements, so we cannot declare it as an array in advance.
Now, I want to copy all of its contents into another array, as efficiently as possible. I know the nested loop solution where we copy each element one by one, however, it seems extremely inefficient to me. Is there a way to speed this process up? C++ code is welcome, although I would prefer it in plain C, since I am planning to iterate this solution into Objective C, and I would like to avoid injecting C++ code into a clean Objective C project.
Can anyone point me in the right direction?
Using what you already have (but fixing the first malloc with sizeof(char***))
You could copy the array by running a bunch of for loops like this:
char new_cube[side][side][side];
for(unsigned int x = 0; x < side; x++)
for(unsigned int y = 0; y < side; y++)
for(unsigned int z = 0; z < side; z++)
new_cube[x][y][z] = old_cube[x][y][z];
OR:
char new_cube[side][side][side];
for(unsigned int x = 0; x < side; x++)
for(unsigned int y = 0; y < side; y++)
memcpy(new_cude[x][y], old_cube[x][y], sizeof(char)*side);
which might be a bit faster.
using this method you avoid using any c++(as you said you would like) and your code complexity is kept minimal.
If you are using C.99, you can use a variable length array (VLA) to dynamically allocate your 3-dimensional array. Once side is determined, you can declare your pointer to be:
char (*cube3d_)[side][side];
And then initialize it like this:
cube3d_ = malloc(side * sizeof(*cube3d_));
Note that in C, you are not required to cast the return value of malloc(), and doing so can actually lead to undefined behavior in the worst case. Since the "cube" has been allocated as a contiguous block, it can be copied with memcpy().
C++ does not have VLA. You can use a vector to get the C++ equivalent of your multi-dynamic allocation structure:
std::vector<std::vector<std::vector<char> > >
cube3d_(side, std::vector<std::vector<char> >(side, std::vector<char>(side)));
You can then copy it using a copy constructor or an assignment.
If cube3d_ is a member variable of an object/structure, so long as your object knows the value of side, you can still use a VLA pointer to access the memory. For example:
struct Obj {
size_t side_;
void *cube3d_;
};
//...
size_t side = 3;
//...
Obj o;
o.side_ = side;
char (*p)[o.side_][o.side_] = malloc(o.side_ * sizeof(*p));
o.cube3d_ = p;
//...
char (*q)[o.side_][o.side_] = o.cube3d_;
q[1][2][2] = 'a';
Here is an approach using C and structs to provide some degree of object oriented along with a set of helper functions.
The idea here was to use Kerrick's suggestion of a contiguous array.
I am not sure if I got the offset calculation correct and it has not been tested so it is worth what you are paying for it. However it may be helpful as a starting place.
The idea is to have a single contiguous area of memory to make memory management easier. And to use a function to access a particular element using a zero based offset in the x, y, and z directions. And since I was not sure as to the element size/type, I made that a variable as well.
#include <malloc.h>
typedef struct _Array3d {
int elSize; // size of each element of the array in bytes
int side; // length of each side of the 3d cube in elements
char * (*Access) (struct _Array3d *pObj, int x, int y, int z);
char buffer[1];
} Array3d;
static char * Array3d_Access (Array3d *pObj, int x, int y, int z)
{
char *pBuf = NULL;
if (pObj && x < pObj->side && y < pObj->side && z < pObj->side) {
pBuf = &(pObj->buffer[x * pObj->side * pObj->elSize * pObj->side * pObj->elSize + y * pObj->side * pObj->elSize + z * pObj->elSize]);
}
return pBuf;
}
// Create an Array3d cube by specifying the length of each side along with the size of each element.
Array3d *Array3d_Factory (int side, int elSize)
{
Array3d *pBuffer = malloc (sizeof(Array3d) + side * elSize * side * elSize * side * elSize);
if (pBuffer) {
pBuffer->elSize = elSize;
pBuffer->side = side;
pBuffer->Access = Array3d_Access;
}
return pBuffer;
}
// Create an Array3d cube that is the same size as an existing Array3d cube.
Array3d *Array3d_FactoryObj (Array3d *pObj)
{
Array3d *pBuffer = NULL;
if (pObj) {
int iBufferSize = pObj->side * pObj->elSize * pObj->side * pObj->elSize * pObj->side * pObj->elSize;
pBuffer = malloc (sizeof(Array3d) + iBufferSize);
if (pBuffer) {
pBuffer->elSize = pObj->elSize;
pBuffer->side = pObj->side;
pBuffer->Access = pObj->Access;
}
}
return pBuffer;
}
// Duplicate or clone an existing Array3d cube into new one.
// Returns NULL if cloning did not happen.
Array3d *Array3d_Dup (Array3d *pObjDest, Array3d *pObjSrc)
{
if (pObjSrc && pObjDest && pObjSrc->elSize == pObjDest->elSize && pObjSrc->side == pObjDest->side) {
int iBufferSize = pObjSrc->side * pObjSrc->elSize * pObjSrc->side * pObjSrc->elSize * pObjSrc->side * pObjSrc->elSize;
memcpy (pObjDest->buffer, pObjSrc->buffer, iBufferSize);
} else {
pObjDest = NULL;
}
return pObjDest;
}
int main(int argc, _TCHAR* argv[])
{
Array3d *pObj = Array3d_Factory (10, 20 * sizeof(char));
char *pChar = pObj->Access (pObj, 1, 2, 3);
return 0;
}
I am trying to pass an int array around. Below is an example of what I want to do. Basically, I can write a function that returns an int array by returning a pointer. Now I want to take that function and use it as an argument to another function. The goal is to have one function create an int array and then this goes into another function that takes an int array as an input. It doesn't work. Inside the function that takes the int * pointer, the int * pointer just becomes -8435432 and can't have its elements read after it is assigned to another int * pointer. I don't get it. Why can I get an int array back from a function but this can't then be used as an input to another function?
int * returnIntArray()
{
int * thePointer;
int j[3];
thePointer = j;
j[0] = 1;
j[1] = 3;
j[2] = -1;
return thePointer;
}
//
int * takesTheIntArray(int * anIntArray)
{
int x,y,z;
int * returnIt;
returnIt = anIntArray;
x = returnIt[0];
y = returnIt[1];
z = returnIt[3];
return returnIt;
}
int _tmain(int argc, _TCHAR* argv[])
{
int y,z,p;
int * x;
x = returnIntArray();
y = x[0];
z = x[1];
x = takesTheIntArray(returnIntArray());
cout << x[0] << ", " << x[1];
//cout << theVector[1];
cout << "hello";
}
int * thePointer;
int j[3];
thePointer = j;
Should be:
int* thePointer = new int[3];
The problem with the first version is that you're returning something that is statically allocated (allocated on the stack). It will go out of scope when the function returns. In the second version it's dynamically allocated (allocated on the heap). Remember to call delete[] on thePointer once you're finished (or else you leak memory).
You can rewrite returnIntArray() as following:
int * returnIntArray()
{
static int j[3];
j[0] = 1;
j[1] = 3;
j[2] = -1;
return j;
}
You don't need the "thePointer" variable that only hides the fact that your j was a local variable destroyed at the end of the scope. You may have tried without the "thePointer" variable and obtained a "warning C4172: returning address of local variable or temporary" meaning the value you return won't be valid after returning (the same problem you have with thePointer). The static before j declaration makes the j global (but only available by its name in the function) so values contained by j won't be lost at the end of the scope.
I did not understand what was the point of "takesTheIntArray" maybe a debug purpose to see x, y, z values in debugger? if this is the case you don't need to copy the pointer and can simply do:
//
int * takesTheIntArray(int * anIntArray)
{
int x,y,z;
x = anIntArray[0];
y = anIntArray[1];
z = anIntArray[2];
return anIntArray;
}
Keep your main and this should work as you want :)
[edit] there was a typo in the "takesTheIntArray" I didn't noticed when reposting: the anIntArray index for z var should be 2 and not 3[/edit]
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.