Class 2D array turns to arr [] when called by function C++ - c++

I have a university assignment and I am completely confused on how to pass the array correctly to prevent the array from being passed as a single array and not a 2D array.
We are to create a random maze generator that will allow us to play that maze too. We are using a specialized windows code to display the maze, but that's not were the problem is so Ill leave that out
My lecturer gave us the skeleton code to work from. What must I change to get it to work?
We have not learnt dynamic memory location or vectors. We have to use an array. Please Help!!?
Here is his code:
I have used the same and just added all the function parameters. I have not changed anything with 'maze' though
class MazeSquare
{
public:
bool leftWall, rightWall, bottomWall, topWall;
bool visited;
int steps;
MazeSquare() // constructor
{
Initialise();
}
void Initialise(void) // reinitialise a square for a new maze
{
leftWall = true; // create the maze square with all the walls
rightWall = true;
bottomWall = true;
topWall = true;
visited = false; // the robot has not visited the square yet
steps = 256; // greater than maximum possible number of steps
}
};
// constants
const int MAZE_SIZE = 16;
// function prototypes
void CreateMaze(MazeSquare maze[MAZE_SIZE][MAZE_SIZE]);
void SolveMaze(MazeSquare maze[MAZE_SIZE][MAZE_SIZE]);
void RestartMaze(MazeSquare maze[MAZE_SIZE][MAZE_SIZE]);
void MoveRobot(MazeSquare maze[MAZE_SIZE][MAZE_SIZE], int &x, int &y, Point click);
void DrawWindow(MazeSquare maze[MAZE_SIZE][MAZE_SIZE], int x, int y);
int ccc_win_main() // main function for a graphics program
{
MazeSquare maze[MAZE_SIZE][MAZE_SIZE]; // maze design
int x = 0, y = 0; // robot position
bool exit = false; // flag to control end of program
// initialise the random number generator
srand((unsigned int)(time(NULL)));
/* initialise the window coordinates here */
CreateMaze(maze); // create a new maze
DrawWindow(maze); // draw the image in the GUI window
do
{
// get a mouse click
Point click = cwin.get_mouse("Click a button or move the robot");
// handle the different types of mouse clicks
if (/* new button is clicked */)
{
CreateMaze(maze);
x = 0;
y = 0;
}
if (/* solve button is clicked */)
{
SolveMaze(maze);
}
if (/* restart button is clicked */)
{
RestartMaze(maze);
x = 0;
y = 0;
}
if (/* exit button is clicked */)
{
exit = true;
}
// handle robot moves
if (/* maze is clicked */)
{
MoveRobot(maze, x, y);
}
DrawWindow(maze);
} while (!exit);
return 0;
}

Confusion number one - You cannot pass arrays to functions in C++.
Confusion number two - You cannot declare arrays as function parameters in C++
Confusion number three - 2D arrays are single arrays, a 2D array is an arrays of arrays, therefore it's a 'single array` also. I guess I'm saying the term single array doesn't have much meaning.
Arrays are a confusing topic in C++. You cannot do everything you might expect to be able to do with them. Instead everything is done with pointers. The relationship beween arrays and pointers in C++ is another confusing topic. You really need to read a book. Any specific questions, ask again.
But on the bright side I don't see anything particularly wrong with your code. You're certainly are not passing single arrays to your functions, as you are worried about.
EDIT:
Perhaps I should make this a little clearer. On point two, this code
void CreateMaze(MazeSquare maze[MAZE_SIZE][MAZE_SIZE]);
certainly looks like you are declaring a function with an array parameter. But it doesn't. Instead the compiler takes the code and converts it into the equivalent code that uses pointers.
On point one, this code
CreateMaze(maze); // create a new maze
certainly looks like you are passing an array to a function, but again you are not. Given that code the compiler passes a pointer to the first element of your maze array, it doesn't pass the array itself.

Related

Undefined reference to scene_render

Here is the following main function or my program
void scene_render(const struct Scene *s);
int main(void) { //leave main as is
struct Scene myScene;
scene_init(&myScene);
int keep_going = 1;
while (keep_going == 1) {
cons_clear_screen(); //clear off-screen display buffer
scene_render(&myScene); //render the scene to display buffer
cons_update(); //copy the display buffer to the display
cons_sleep_ms(ANIMATION_DELAY); //pause
scene_update(&myScene); //update the scene
int key = cons_get_keypress(); //see if the user has pressed a key
if (key != -1) {
keep_going = 0;
}
}
return 0;
}
void scene_render(Scene *s)
{
cons_clear_screen();
for(int i=0; i<NUM_PARTICLES; i++)
{
particle_render(&s->parts[i]);
}
}
When I run the makefile command on Cygwin, it passes the errors and starts compiling, but hits an error when it hits scene_render(&myScene);. It says that a reference to it is undefined. It refers to a variable in a function that is a const struct, while all other instances where &myScene is called are merely structs. Any idea what the issue may be? This lab is mostly about using pointers, if that helps.
The program (with assistance from external functions) should generate and throw randomly colored pixels around the command window, bouncing them back to keep them in the screen. Deleting the issue causes the program to compile successfully, but then loads a blank window that seems to do nothing.
Problem
With
void scene_render(const struct Scene *s);
you promise scene_render takes a const struct Scene as a parameter. By the way, you can discard the use of struct here. C++ knows Scene is a struct.
But the function that is defined is
void scene_render(Scene *s)
which takes a plain old, non-const Scene, so when the linker goes looking for a function that matches the promise it does not find one.
Solution
Change
void scene_render(Scene *s)
to
void scene_render(const Scene *s)
to keep the promise. But make certain that const-correctness is maintained throughout.

C++ Vector read access violation Mylast returned 0x8

I really need help on this one cause I am extremely stuck and have no idea what to do.
Edit:
A lot of you guys are saying that I need to use the debugger but let me be clear I have not used C++ for an extremely long time and I've used visual studio for a grand total of 2 weeks so I do not know all the cool stuff it can do with the debugger.
I am a student at university at the beginning of my second year who is trying to work out how to do something mostly by failing.
I AM NOT a professional coder and I don't have all the knowledge that you people have when it comes to these issues and that is why I am asking this question. I am trying my best to show my issue so yes my code contains a lot of errors as I only have a very basic understanding of a lot of C++ principles so can you please keep that in mind when commenting
I'm only posting this here because I can don't know who else to ask right now.
I have a function called world that is suppose to call my render class to draw all the objects inside of its vector to the screen.
#include "C_World.h"
C_World::C_World()
{
// creates an instance of the renderer class to render any drawable objects
C_Renderer *render = new C_Renderer;
}
C_World::~C_World()
{
delete[] render;
}
// adds an object to the world vector
void C_World::addToWorld(C_renderable* a)
{
world_list.push_back(a);
}
void C_World::World_Update()
{
render->ClearScreen();
World_Render();
}
void C_World::World_Render() {
for (int i = 0; i < 1; i++)
{
//render->DrawSprite(world_list[i]->getTexture(), world_list[i]->get_X, world_list[i]->get_Y());
render->DrawSprite(1, 1, 1);
}
}
While testing I commented out the Sprites get functions in order to check if they were causing the issue.
the renderer sprites are added to the vector list in the constructor through the create sprite function
C_Renderer::C_Renderer()
{
// test sprite: Id = 1
CreateSprite("WhiteBlock.png", 250, 250, 1);
}
I thought this might of been the issue so I had it in other functions but this didn't solve anything
Here are the Draw and create Sprite functions
// Creates a sprite that is stored in the SpriteList
// Sprites in the spriteList can be used in the drawSprite function
void C_Renderer::CreateSprite(std::string texture_name,
unsigned int Texture_Width, unsigned int Texture_height, int spriteId)
{
C_Sprite *a = new C_Sprite(texture_name,Texture_Width,
Texture_height,spriteId);
SpriteList.push_back(a);
size_t b = SpriteList.size();
HAPI.DebugText(std::to_string(b));
}
// Draws a sprite to the X and Y co-ordinates
void C_Renderer::DrawSprite(int id,int x,int y)
{
Blit(screen, _screenWidth, SpriteList[id]->get_Texture(),
SpriteList[id]->getTexture_W(), SpriteList[id]->getTexture_H(), x, y);
}
I even added some test code into the create sprite function to check to see if the sprite was being added too the vector list. It returns 1 so I assume it is.
Exception thrown: read access violation.
std::_Vector_alloc<std::_Vec_base_types<C_Sprite *,
std::allocator<C_Sprite *> > >::_Mylast(...) returned 0x8.
that is the full error that I get from the compiler
I'm really really stuck if there is anymore information you need just say and ill post it straight away
Edit 2:
#pragma once
#include <HAPI_lib.h>
#include <vector>
#include <iostream>
#include "C_renderable.h"
#include "C_Renderer.h"
class C_World
{
public:
C_World();
~C_World();
C_Renderer *render = nullptr;
void World_Update();
void addToWorld(C_renderable* a);
private:
std::vector<C_renderable*> world_list;
void C_World::World_Render();
};
#pragma once
#include <HAPI_lib.h>
#include "C_renderable.h"
#include "C_Sprite.h"
#include <vector>
class C_Renderer
{
public:
C_Renderer();
~C_Renderer();
// gets a pointer to the top left of screen
BYTE *screen = HAPI.GetScreenPointer();
void Blit(BYTE *destination, unsigned int destWidth,
BYTE *source, unsigned int sourceWidth, unsigned int sourceHeight,
int posX, int posY);
void C_Renderer::BlitBackground(BYTE *destination,
unsigned int destWidth, unsigned int destHeight, BYTE *source,
unsigned int sourceWidth, unsigned int sourceHeight);
void SetPixel(unsigned int x,
unsigned int y, HAPI_TColour col,BYTE *screen, unsigned int width);
unsigned int _screenWidth = 1750;
void CreateSprite(std::string texture_name,
unsigned int Texture_Width,unsigned int Texture_height, int spriteId);
void DrawSprite(int id, int x, int y);
void ClearScreen();
private:
std::vector<C_Sprite*> SpriteList;
};
I don't say this lightly, but the code you've shown is absolutely terrible. You need to stop and go back several levels in your understanding of C++.
In all likeliness, your crash is the result of a simple "shadowing" issue in one or more of your functions:
C_World::C_World()
{
// creates an instance of the renderer class to render any drawable objects
C_Renderer *render = new C_Renderer;
}
C_World::~C_World()
{
delete[] render;
}
There are multiple things wrong here, and you don't show the definition of C_World but if this code compiles we can deduce that it has a member render, and you have fallen into a common trap.
C_Renderer *render = new C_Renderer;
Because this line starts with a type this is a definition of a new, local variable, render. Your compiler should be warning you that this shadows the class-scope variable of the same name.
What these lines of code
C_World::C_World()
{
// creates an instance of the renderer class to render any drawable objects
C_Renderer *render = new C_Renderer;
}
do is:
. assign an undefined value to `this->render`,
. create a *local* variable `render`,
. construct a dynamic `C_Renderer` presumably on the heap,
. assign that to the *local* variable `render`,
. exit the function discarding the value of `render`.
So at this point the memory is no-longer being tracked, it has been leaked, and this->render is pointing to an undefined value.
You repeat this problem in several of your functions, assigning new results to local variables and doing nothing with them. It may not be this specific instance of the issue that's causing the problem.
Your next problem is a mismatch of new/delete vs new[]/delete[]:
C_World::~C_World()
{
delete[] render;
}
this would result in undefined behavior: this->render is undefined, and delete[] on a non-new[] allocation is undefined.
Most programmers use a naming convention that distinguishes a member variable from a local variable. Two common practices are an m_ prefix or an _ suffix for members, e.g.
class C_World
{
public:
C_Foo* m_foo; // option a
C_Renderer* render_; // option b
// ...
}
Perhaps you should consider using modern C++'s concept of smart pointers:
#include <memory>
class C_World {
// ...
std::unique_ptr<C_Renderer> render_;
// ...
};
C_World::C_World()
: render_(new C_Renderer) // initializer list
{}
But it's unclear why you are using a dynamic allocation here in the first place. It seems like an instance member would be better:
class C_World {
C_Renderer render_;
};
C_World::C_World() : render_() {}

C++ STD Vector push_back doesn't seem to work

I'm making a game with SDL that used libconfig to read some settings from a file. The problem is that I made a class called ClipList that contains a std::vector<SDL_Rect> to store the settings but when trying to add SDL_Rect objects to the vector, for some reason push_back does nothing and I end up with an empty vector.
This is the class:
class ClipList
{
public:
ClipList();
ClipList(int);
virtual ~ClipList();
void addClip(int,int,int,int);
void getClip(int,SDL_Rect*);
int getLength();
protected:
private:
std::vector<SDL_Rect> clips;
};
ClipList::ClipList(int l)
{
clips.reserve(l);
}
void ClipList::addClip(int x,int y,int w,int h){
SDL_Rect rect;
rect.x = x;
rect.y = y;
rect.w = w;
rect.h = h;
clips.push_back(rect);
}
void ClipList::getClip(int i,SDL_Rect* rect){
rect = &(clips.at(i));
}
int ClipList::getLength(){
return clips.size();
}
And this is the function where I initialize the ClipList object. This function gets called from main.
void set_clips(Config* placlips,ClipList* clips, ClipList* flipclips){
const Setting& root = placlips->getRoot();
int x,y,w,h;
try{
Setting& clipsett = root["clips"];
int cliplen = clipsett.getLength();
clips = new ClipList(cliplen);
flipclips = new ClipList(cliplen);
for(int i=0;i<cliplen;i++){
const Setting& c = clipsett[i];
if(!(c.lookupValue("x",x)&&c.lookupValue("y",y)&&c.lookupValue("w",w)&&c.lookupValue("h",h))){
continue;
}
clips->addClip(x,y,w,h);
}
}catch(const SettingNotFoundException &nfex){
cerr << "Setting not found at" << nfex.getPath() << endl;
}
}
Regardless of whether the ClipList objects get initialized in main or set_clips, clips.push_back(rect) doesn't work. The capacity of the vector changes but no object gets stored so I end up with a segfault if I try to do anything else with the vector, even checking if the vector is empty or not.
I am going to guess, the signature of the function
void set_clips(Config* placlips,ClipList* clips, ClipList* flipclips);
is the culprit. You are allocating memory for clips and flipclips in this function but since the pointers are passed by value, the calling function does not see the allocated memory.
If you change the function signature to:
void set_clips(Config* placlips, ClipList*& clips, ClipList*& flipclips);
your problems should go away.
clips.push_back(rect) is working fine. Your set_clips function allocates new ClipList instances but does not pass those pointers back to the caller. The caller is probably attempting to use a garbage pointer as an initialise instance and that is why you are getting a segfault.
You need to pass the created objects back. You should use something like std::shared_ptr<> to do that instead of bare pointers.
Update on how to do this without using std::shared_ptr<>:
You need to keep track of ownership and deal with exceptions. In terms of the actual passing, the rule I use (originally from Lakos in "Large Scale C++ Software Design") is that parameters that are return values (as you are attempting to use them) are pointers, and read-only parameters are by value or const-reference. Return values come first.
So, your set_clips function should look like this:
void set_clips(ClipList** clips, ClipList** flip_clips, Config const& placlips)
When you call set_clips you pass a pointer to each pointer that will receive the allocated value, and pass a const-reference to the placlips object that is not modified by the function.
You would all it something like this:
ClipList* clips = 0;
ClipList* flip_clips = 0;
set_clips(&clips, &flip_flips, placlips);
// ... then do whatever comes next.
But combining those rules with std::shared_ptr<> or boost::shared_ptr<> is better and the "modern C++" style.

C++ Accessing and Manipulating 2D Pointer Array from within get function

I am making a battleships game for my coursework, and I have run into some problems with the get functions in one of the classes I am using. The basic idea of my game is to create a 2D 10X10 array, called grid, filled with null pointers to represent the board. I have created 2 classes, Board and Ship. The grid array is of type Ship, and I use an algorithm to fill the array with Ships randomly. I use the Board class to access the grid array and the hits array (which I use to track hits).
However I cannot figure out how the getShips function can return the grid array. The hits array is just booleans so that was easy enough, but I am not proficient enough at C++ to make the getShips function properly return the grid array, which is a Ship pointer type. I would greatly appreciate any help.
class Board
{
private:
Ship *grid[10][10];
bool hits[10][10];
public:
// get functions
Ship *getShips()
{
return grid;
}
bool getHits()
{
return hits;
}
};
I was also wondering if it would be possible to manipulate the array in other functions by calling the getShips function. Something like:
for (int x=0; x<10; x++)
{
for (int y=0; y<10; y++)
{
board.getShips()[x][y]=nullptr;
}
}
Ok. First I would modify the getShips and getHits functions. To have something like that :
Ship *getShips(int x, int y){ return grid[x+y*10]; }
bool getHits(int x, int y){return hits[x+y*10];}
That way you'll simplify your code and avoid some errors.
When you declare a multidimensional array like you do with
Ship *grid[10][10];
bool hits[10][10];
you're basically declaring pointers to pointers to pointers to ships.
I would try to use a minimum amount of pointers if you're writing in C++. Try to use the stl containers instead. They do automatic memory management for you which may save you some time down the road.
I suggest to change your interface to something like:
class Board
{
private:
Ship *grid[10][10];
bool hits[10][10];
public:
Ship* getShip(int x, int y) const { return grid[x][y]; }
Ship*& getShip(int x, int y) { return grid[x][y]; }
bool getHit(int x, int y) const { return hits[x][y]; }
bool& getHit(int x, int y) { return hits[x][y]; }
};
If you really want to return grid and hits, I recommend to use std::array<std::array<Ship*, 10>, 10> grid; (require C++11) instead of Ship *grid[10][10];.
if C++11 is not possible turn back to std::vector.
and then
private:
std::array<std::array<Ship*, 10>, 10> grid;
public:
const std::array<std::array<Ship*, 10>, 10>& getShips() const { return grid; }
std::array<std::array<Ship*, 10>, 10>& getShips() { return grid; }
Currently, it looks like getShips is returning the entire 10x10 array of Ship*-- you need to change what the getShips function is returning:
Ship*** getShips() { ...
However, I would recommend against mixing pointers and arrays. Pointers can be tricksy, and combining with arrays can get very difficult to debug. Instead, you could use all pointers: Ship ***grid; and initialize with new (I'll leave the initialization as an exercise, but here's a site that has an example: http://pleasemakeanote.blogspot.com/2010/07/2d-arrays-in-c-using-new.html).
In reality, it might be better for the Ship class to store the indices of where it exists, perhaps something like this:
class Ship
{
public:
<<member func>>
private:
int nspaces_;
int start_[2];
int end_[2];
}
where you store the beginning index and the final index where the ship is found. You'll need to handle the code to identify the spaces between, but that is trivial. This setup would allow you to replace Ship *grid[10][10] with a single array of Ships.
The getShips function would then become:
...
Ship ships_[<<number of ships>>];
Ship *getShips()
{
return ships_;
}
...
and would be used:
board.getShips()[x][y]
Or...you could add a getShip(int x, int y) method.

Member not declared in scope?

So I'm trying my hand at some C++ after finishing up an introductory book, and I've become stuck. I've made a vector of objects that each have an SFML circle object as a member, and I want main() to go and draw these circles. The vector is called theBoard, but when I try to access it, I get the following error messages:
error: request for member 'theBoard' in 'GameBoard', which is of non-class type 'Board*'
error: 'theBoard' was not declared in this scope
I'm new to this (came from two years of Python), so I'm sure I made a mistake somewhere. Here is the relevant code for the board creation:
class Board
{
public:
//These are the member functions.
Board();
~Board();
vector<Space*> CreateBoard();
//This will be the game board.
vector<Space*> theBoard;
//These clusters represent the waiting areas for pieces not yet in the game.
vector<Space*> Cluster1;
vector<Space*> Cluster2;
vector<Space*> Cluster3;
private:
//These integers represent the number of spaces on each row, starting at the top (which is row [0])
vector<int> RowNums;
};
Board::Board()
{
//Fill in RowNums with the right values.
RowNums.push_back(1);
RowNums.push_back(17);
RowNums.push_back(2);
RowNums.push_back(17);
RowNums.push_back(1);
RowNums.push_back(1);
RowNums.push_back(5);
RowNums.push_back(2);
RowNums.push_back(7);
RowNums.push_back(2);
RowNums.push_back(11);
RowNums.push_back(3);
RowNums.push_back(17);
RowNums.push_back(4);
RowNums.push_back(17);
//Then, create the board.
theBoard = CreateBoard();
}
CreateBoard() is a very, very long function that returns a vector of pointers to Space objects. I doubt there's a problem here, as the only error message I get crops up when I try to access the circle members of Space objects in main(). It seems to me as though I have declared theBoard in the relevant scope, that is, as a data member of the Board class.
My main() function, in case it's important:
int main()
{
//This sets up the display window.
sf::RenderWindow App(sf::VideoMode(1200, 900, 32), "Malefiz");
//This creates the board on the heap, and a pointer to it.
Board* GameBoard = new Board();
cout << "Board made.";
//This is the game loop.
while(App.IsOpened())
{
//This is used to poll events.
sf::Event Event;
while(App.GetEvent(Event))
{
//This closes the window.
if(Event.Type == sf::Event::Closed)
{
App.Close();
}
}
//This gets the time since the last frame.
//float ElapsedTime = App.GetFrameTime();
//This fills the window with black.
App.Clear(sf::Color(200, 200, 125));
//This draws the places into the window.
for(int i = 0; i < GameBoard.theBoard.size(); ++i)
{
App.Draw(GameBoard.*theBoard[i].m_Circle);
}
//This displays the window.
App.Display();
}
return EXIT_SUCCESS;
}
In your main() function, GameBoard is a Board *, not a Board. So to access members, you need to use -> instead of .. e.g.:
GameBoard->theBoard.size()
[Some people (I am one of them) like to name their pointer variables with a leading p or ptr prefix, in order to make this kind of irritation explicitly clear.]
GameBoard is a pointer to a Board object, and thus you need to use the "->" operator instead of the "." operator to access any of its member variables or methods.
The error is quite explicit if you read it carefully:
error: request for member 'theBoard' in 'GameBoard', which is of non-class type 'Board*'
error: 'theBoard' was not declared in this scope
The first line is telling you that you have a pointer to a Board object and you are trying to access a member directly. That is:
Board *p = ...
p.theBoard; // Error, should be p->theBoard, as p is a pointer
Also note that GameBoard.*theBoard[i].m_Circle might not be what you want, you probably want (I am guessing as there are important bits missing) something like GameBoard->theBoard[i]->m_Circle.
GameBoard is a pointer, so the syntax should be this:
for(int i = 0; i < GameBoard->theBoard.size(); ++i)
{
App.Draw((GameBoard->theBoard[i])->m_Circle);
}
Since elements of theBoard also are pointer, so I used the pointer notation when accessing m_Circle.