Segmentation Fault - altering struct (within another struct's) variables - c++

I have this, in my header:
struct Surface {
char *objectName;
int xPos;
int yPos;
SDL_Surface *surface;
};
struct WorldSurface {
Surface *surface = new Surface[MAX_SURFACES];
int counter = 0;
int current = 0;
};
WorldSurface *worldSurface;
I then initialize the worldSurface in the .cpp:
WorldSurface *worldSurface = new WorldSurface[MAX_LEVELS];
And this function, I can't get to work no matter what, have tried messing around with = NULL, pointers, the -> instead of .'s... (do have in mind I'm not very savvy of pointer subjects)
void drawClass::addSurface(char* objectName, char* surfaceFile, int xPos, int yPos, int drawLevel) {
int cnt = worldSurface[drawLevel].counter;
worldSurface[drawLevel].surface[cnt].objectName = objectName;
worldSurface[drawLevel].surface[cnt].surface = load_image(surfaceFile);
worldSurface[drawLevel].surface[cnt].xPos = xPos;
worldSurface[drawLevel].surface[cnt].yPos = yPos;
worldSurface[drawLevel].counter++;
}
It's 10 worldSurfaces, each containing 50 surface structs, and I want to acess the struct, which is inside the worldSurface[drawLevel], and the surface struct I want to access is known in the worldSurface, in the .counter variable. But all of the acesses to the underlying surface struct fail with segmentation fault, and I have no clue why...
Thanks for the help!

Your WorldSurface isn't defined nor initialized properly:
struct WorldSurface {
Surface *surface = new Surface[MAX_SURFACES];
int counter = 0;
int current = 0;
};
You can't initialize your data in place along with the declaration of the class. You need to do this in a constructor, e.g.:
struct WorldSurface {
Surface *surface;
int counter;
int current;
};
...
WorldSurface::WorldSurface():
counter(0),current(0),surface(new Surface[MAX_SURFACES]){}

Related

Issues dynamic allocation of classes

I am currently trying to refresh my c++ skills with implementing a snake-game. I have created following class - relevant code snippet:
snake_class.h
#include <string>
#include <vector>
#include <windows.h>
typedef struct coordinates {
int x;
int y;
};
class Snake {
public:
std::vector<coordinates> body;
Snake(const int MAX_HEIGHT, const int MAX_WIDTH, const int initLengthSnake);
void updateSnakeBody(coordinates newDirection, int startingPoint);
};
... and with the corresponding code snippet of the .cpp-file:
snake_class.cpp
#include <vector>
#include "snake_class.h"
Snake::Snake(const int MAX_HEIGHT, const int MAX_WIDTH, const int initLengthSnake) {
for (int snakeLength = 0; snakeLength < initLengthSnake; snakeLength++) {
coordinates currentBodyPoint = { (MAX_WIDTH + initLengthSnake) / 2 - snakeLength, (MAX_HEIGHT) / 2 };
body.push_back(currentBodyPoint);
}
}
void Snake::updateSnakeBody(coordinates newDirection, int startingPoint) {
coordinates currentBodyPoint = body[startingPoint];
body[startingPoint].x += newDirection.x;
body[startingPoint].y += newDirection.y;
if (startingPoint + 1 < body.size()) {
coordinates nextDirection = { currentBodyPoint.x - body[startingPoint + 1].x,
currentBodyPoint.y - body[startingPoint + 1].y };
updateSnakeBody(nextDirection, startingPoint + 1);
}
}
My main-method looks like the following:
bool crashed = false;
int main()
{
//init-part for windows and snake length
const int windowHeight = 20;
const int windowWidth = 25;
const int initSnakeLength = 4;
//init part for snake game to move and some stock variables
coordinates direction = { 1, 0 };
bool initNeeded = false;
//snake init
Snake* snake = new Snake(windowWidth, windowHeight, initSnakeLength);
while (true) {
if (initNeeded) {
crashed = false;
Snake* snake = new Snake(windowWidth, windowHeight, initSnakeLength);
initNeeded = false;
}
if (!crashed) {
(*snake).updateSnakeBody(direction, 0);
crashed = true;
}
else {
delete snake;
initNeeded = true;
}
}
return 0;
}
Build is successfull and the first round of the game works as expected. When I feedback to the game, that I want to play another round, then the new snake class is constructed once again inside the if (initNeeded) {...}-condition. The vector also got the size of 4 after the construction.
But as soon as the program enters the line
(*snake).updateSnakeBody(direction, 0);
I retrieve the error-message vector subsrictp out of range and somehow the vector got the size 0.
I know, that I do not need to dynamically allocate a new class for getting the game to run as intended, but I wanted to try it out in this way.
I cannot really figure out why the new class behaves like that and hope some of you could help me resolving that issue!
Thanks in advance!
You construct two different snakes, one in the main scope, on in the scope of the if statement. Then you create two pointers to these, with the same name. You need to sort this out!
while (true) {
if (initNeeded) {
crashed = false;
Snake* snake = new Snake(windowWidth, windowHeight, initSnakeLength);
initNeeded = false;
}
This snake pointer cannot be accessed from anywhere else. Whatever you are trying to do, this must be wrong.
Perhaps this is what you meant to do
//declare snake pointer
Snake* snake;
while (true) {
if (initNeeded) {
crashed = false;
// set pointer to a new snake
snake = new Snake(windowWidth, windowHeight, initSnakeLength);
initNeeded = false;
}

Creating a 2D Array of a Class C++

I'm using a C++ engine called libtcod to print out ASCII characters in a rogue-like game.
In the game I want to represent the 'map' as a 2D array of type Map, which contains 'layer1' for tiles, e.g Grass, Sand, Water, and a second layer to represent objects on top of layer2, e.g Trees and Boulders.
I have created the Map class, which contains two attributes; one of type Tile, and the other of type Object.
However I seem to be having difficulties in the creation of the 2D array itself.
I am getting the error: "an array may not have elements of this type"
#include "libtcod.hpp"
#include <ctime>
#include <stdio.h>
#include <ciso646>
#include <cstring>
static const TCODColor colour_darkWall(128, 128, 128);
static const TCODColor colour_grass(0, 255, 0);
static const TCODColor colour_black(0, 0, 0);
static const TCODColor colour_white(255, 255, 255);
static const TCODColor colour_blue(0, 0, 255);
static const TCODColor colour_brown(139, 69, 19);
static const TCODColor colour_red(255, 0, 0);
int i, j;
class object {
public:
char name[20];
TCODColor colour;
char symbol;
bool passable;
object(int layer_id) {
if (layer_id == 0) { //EMPTY
strcpy(name, "NA");
symbol = ' ';
passable = true;
colour = colour_white;
}
else if (layer_id == 1) { //TREE
strcpy(name, "Tree");
symbol = '^';
passable = false;
colour = colour_grass;
}
else if (layer_id == 2) { //ROCK
strcpy(name, "Rock");
symbol = 'R';
passable = false;
colour = colour_black;
}
}
};
class tile {
public:
char name[20];
TCODColor colour;
bool passable;
tile(int layer_id) {
if (layer_id == 0) { //WATER
strcpy(name, "Water");
colour = colour_blue;
passable = false;
}
else if (layer_id == 1) { //GRASS
strcpy(name, "Grass");
colour = colour_grass;
passable = true;
}
else if (layer_id == 2) { //SAND
strcpy(name, "Sand");
colour = colour_brown;
passable = true;
}
}
};
class Map {
public:
tile layer1;
object layer2;
Map(int layer1_id, int layer2_id) {
layer1 = tile(layer1_id);
layer2 = object(layer2_id);
}
};
int main() {
const int window_x = 150;
const int window_y = 50;
Map[][] map = new Map[5][5];
TCODConsole::initRoot(window_x, window_y, "CivSim v0.1", false);
while (!TCODConsole::isWindowClosed()) {
TCODConsole::root->clear();
TCODConsole::root->putChar(0, 0, map.layer2.symbol);
TCODConsole::flush();
}
return 0;
}
Not sure how to create the 2D array in question.
Thanks in advance for any help!
Map[][] map = new Map[5][5]; is not legal. Only the first dimension can be omitted. You need Map[][5] map = new Map[5][5]; or better still Map (*map)[5] = new Map[5][5];.
The reason is that these notations using [] in a type are just another (and confusing) way of describing a pointer type. So int[] x is just a different way of writing int* x and Map[][5] m is just another way of writing Map (*m)[5] (which is to say a pointer to an array of five Maps).
I think you should always use the pointer version of these notations, it's more correctly describes what you are really doing. In the long term writing code that looks like you have an array, when all you actually have is a pointer is confusing.
So why isn't Map[][] another way of writing Map**? It's because the similarity between arrays and pointer in C and C++ only works for one level. A two dimensional array is a fundamentally different structure from a pointer to an array of pointers. So int[5][5] isn't compatible with int** so there is no reason to make int[][] mean the same as int**.

Declare pointer as class member C++

I'm trying to write a C++ class with a couple of pointers to ints as private members.
I get this exception when trying to assign a value to the pointer address:
Unhandled exception at 0x000B140A in test.exe: 0xC0000005: Access violation writing location 0x00000000.
Here is the minimum amount of code that will reproduce the problem on my machine
#include "stdafx.h"
class Chunker {
public:
Chunker(int cx, int cy);
private:
int chunkSizeX, chunkSizeY;
int *yOff, *xOff;
};
Chunker::Chunker(int cx, int cy){
chunkSizeX = cx;
chunkSizeY = cy;
*xOff = 0;
*yOff = 0;
};
int main(int argc, char *argv)
{
Chunker chunker(12, 12);
return 0;
}
I just can't figure out what is wrong here?
You need to declare memory somewhere for your pointers
Chunker::Chunker(int cx, int cy)
: chunkSizeX{cx},
chunkSizeY{cy}
{
xOff = new int(0);
yOff = new int(0);
}
Otherwise you are assigning a value to a pointer that does not yet have an address.
Obviously if your class is the one that allocates the memory, you need to clean it up too
Chunker::~Chunker()
{
delete xOff;
delete yOff;
}
If your class is the one allocating memory, you also might want to consider having the members be
std::unique_ptr<int> xOff;
std::unique_ptr<int> yOff;
Alternative to #Cuber's reply is to replace *xOff = 0; by xOff = nullptr; (without the *). But why pointers?
Chunker::Chunker(int cx, int cy)
: chunkSizeX{cx},
chunkSizeY{cy}
{
xOff = nullptr;
yOff = nullptr;
}
...
Chunker::~Chunker()
{
delete xOff;
delete yOff;
}

Array of object C++

In the image below (Character.cpp), may I know how to create only one Initialize method that can be called to stored many sprites? Do I need to change the Texture1,Sprite,PosX,PosY, etc to array?
The initialize method will be called in my MAIN.cpp. Sorry if the explaination is not good enough. That is just my idea of doing it but will there be a better ones instead of having so many arrays?
void Character::Initialize1(string image1, float PosX1, float PosY1, float CenterX1, float CenterY1)
{
D3DXCreateTextureFromFile(Pull->GETd3ddev(), image.c_str(), &Texture1);
D3DXCreateSprite(Pull->GETd3ddev(), &sprite1);
RECT SpriteRect1;
SpriteRect1.top = 0;
SpriteRect1.bottom = 127;
SpriteRect1.left = 0;
SpriteRect1.right = 128;
SpritePos1 = D3DXVECTOR2(PosX1, PosY1);
SpriteCenter1 = D3DXVECTOR2(CenterX1, CenterY1);
}
void Character::Initialize2(string image2, float PosX2, float PosY2, float CenterX2, float CenterY2)
{
D3DXCreateTextureFromFile(Pull->GETd3ddev(), image.c_str(), &Texture2);
D3DXCreateSprite(Pull->GETd3ddev(), &sprite2);
RECT SpriteRect2;
SpriteRect2.top = 0;
SpriteRect2.bottom = 14;
SpriteRect2.left = 0;
SpriteRect2.right = 14;
SpritePos2 = D3DXVECTOR2(PosX2, PosY2);
SpriteCenter2 = D3DXVECTOR2(CenterX2, CenterY2);
}
Create the necessary initialization method in your sprite class. Then in main() create your sprites and call the appropriate initialization methods. If using lots of Sprites, it will be probably handy to put the created sprites inside a vector in order to have less code for cleanup and probably other things.
A quick example for a Sprite class called SpriteConfig, which only contains position parameters.
#include <iostream>
#include <vector>
using namespace std;
class SpriteConfig {
public:
SpriteConfig() {
top = 0;
bottom = 0;
left = 0;
right = 0;
}
void setPos(float aTop, float aBottom, float aLeft, float aRight) {
mTop = aTop;
mBottom = aBottom;
mLeft = aLeft;
mRight = aRight;
}
private:
// position parameters
float mTop;
float mBottom;
float mLeft;
float mRight;
};
int main()
{
vector<SpriteConfig*> spriteConfigs;
SpriteConfig *sprCfg;
sprCfg = new SpriteConfig();
sprCfg->setPos(1,1,1,1);
spriteConfigs.push_back(sprCfg);
sprCfg = new SpriteConfig();
sprCfg->setPos(2,2,2,2);
spriteConfigs.push_back(sprCfg);
// We now have a number of Sprites
// Add code here to do something with it.
// ...
for(vector<SpriteConfig*>::iterator it = spriteConfigs.begin();
it != spriteConfigs.end();
++it) {
// cleanup
delete (*it);
(*it) = null;
}
return 0;
}

Array of structs declaration

I am trying to write this C++ function in which I am trying to set each Sequence in the array of Sequences, however when I follow the code on debug I notice that the array is not changing. In particular:
compressed.data[compressedDataCounter].c = pic.data[i];
compressed.data[compressedDataCounter].times = counter+1;
don't seem to add any new variables to the array, just override the first one.
I am thinking that the root of the problem is the declaration:
CompressedPic compressed;
compressed.data = new Sequence[pic.height * pic.width];
This is the portion of the code:
struct Sequence
{
char c;
int times;
};
struct CompressedPic
{
int height;
int width;
Sequence* data;
};
struct Picture
{
int height;
int width;
char* data;
};
CompressedPic compressThePicture(Picture pic) {
CompressedPic compressed;
compressed.data = new Sequence[pic.height * pic.width];
compressed.height = pic.height;
compressed.width = pic.width;
int compressedDataCounter=0;
for(int i=0; i<(pic.height * pic.width)-1; i++)
{
int counter = 0;
while(pic.data[i] == pic.data[i+1])
{
i++;
counter++;
}
compressed.data[compressedDataCounter].c = pic.data[i];
compressed.data[compressedDataCounter].times = counter+1;
compressedDataCounter++;
}
compressed.data[compressedDataCounter].times = -1;
return compressed;
}
It would be great if someone could figure out why this is happening.
You might want to change:
compressed.data[compressedDataCounter].c = counter+1;
to:
compressed.data[compressedDataCounter].times = counter+1;
So you can change the .times member otherwise you will be overriding your .c member. Right now you are setting .c to 'a' for example. Then you set .c to 103 (counter+1). Which is an int and likely with your archetecture the high bytes are aligning with .c and setting it to 0 as well.
So .c is getting 0'd and .times is never set