Cannot access global array in main after initializing in another function - c++

I'm having a hard time understanding why I cannot access my global 2D array in my main function after I have initialized it already in another function.
EDIT: Forgot to specify that d is a known int variable declared before all of this, usually 3 or 4.
void init();
int **board;
int main(){
init();
cout << board[0][0];
}
void init(){
int **board = new int*[d];
for (int i = 0; i < d; i++){
board[i] = new int[d];
}
int n=d*d;
for (int i = 0; i < d; i++){
for (int j = 0; j < d; j++){
board[i][j] = n;
n--;
}
}
So the moment I try to access board[0][0] in main() I get an "Access violation at 0x00000000".
I enter debugging and see that board[0][0] points to 0x000000 when being called in main() but if I try to call it in the init() function, at the end for example, it works perfectly and I can access any variable.

You're creating a new temporary variable:
int **board = new int*[d];
This is a memory leak and you cannot access the memory after the function. You can just do this:
board = new int*[d]; //remember to delete []!
I see you have tagged your question [c++]. If this is the case, you should be using the standard library instead of dealing with raw pointers. std::vector and std::array come to mind.

void init(){
int **board = new int*[d];
Here, you are defining a local variable board in the function which blocks the global variable board.
Instead, assign the value directly, don't define another variable:
void init(){
board = new int*[d];

Related

The array in my singleton isn't keeping information after leaving a function and then it crashes when it tries to access the information again

I have an array called int **grid that is set up in Amazon::initGrid() and is made to be a [16][16] grid with new. I set every array value to 0 and then set [2][2] to 32. Now when I leave initGrid() and come back in getGrid() it has lost its value and is now 0x0000.
I don't know what to try, the solution seems to be really simple, but I'm just not getting it. Somehow the data isn't being kept in g_amazon but I could post the code.
// Returns a pointer to grid
int** Amazon::getGridVal()
{
char buf[100];
sprintf_s(buf, "Hello %d\n", grid[2][2]);
return grid;
}
int Amazon::initGrid()
{
int** grid = 0;
grid = new int* [16];
for (int i = 0; i < 16; i++)
{
grid[i] = new int[16];
for (int j = 0; j < 16; j++)
{
grid[i][j] = 0;
}
}
grid[2][2] = 32;
return 0;
}
int **grid;
g_amazon = Amazon::getInstance();
g_amazon->initGrid();
grid = g_amazon->getGridVal();
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
int index;
index = (width * 4 * i) + (4 * j);
int gridval;
gridval = grid[i][j];
lpBits[index] = gridval;
lpBits[index + 1] = gridval;
lpBits[index + 2] = gridval;
}
}
It crashes when I run it at the line where sprintf_s prints out [2][2] and it also crashes when I get to gridval = grid[i][j] because it's at memory location 0x000000.
The variable
int** grid
in the initGrid() function is a local variable. Edit** When the function returns the variable is popped off the stack. However, since it was declared with the new operator the memory still exists on the heap; it is simply just not pointed to by your global grid variable.
#Dean said in comment:
I have grid as an int** grid; in class Amazon {}; so shouldn't it stay in memory or do I need a static var.
That is the problem:
local int **grid; on Amazon::initGrid::
is masking
member int **grid; on Amazon::
as the first context has higher priority in name lookup.
So initGrid() allocates memory referenced only by a local pointer. That pointer no longer exists when you return from this function, Amazon::grid was never touched on initialization and you're also left with some bad memory issues.
So, as commented by #Remy-Lebeau, I also suggest
Consider using std::vector> or std::array, 16> instead. There is no good reason to use new[] manually in this situation.

C++ 2D Array Initialization In Constructor - Program Runs Forever

I have a small class that creates a 2D array based on a variable size. The code I have for the class is as follows
class Treasure
{
int** board;
int size;
public:
Treasure(int boardSize)
{
board = new int* [boardSize];
for (int i = 0; i < size; i ++)
{
board[i] = new int[boardSize];
}
size = boardSize;
}
~Treasure()
{
for (int i = 0; i < size; i++)
{
delete [] board[i];
}
delete [] board;
board = NULL;
size = 0;
}
int get_value(int row, int col)
{
return board[row][col];
}
void set_value(int row, int col, int value)
{
board[row][col] = value;
}
};
I wanted to test my getter so I just ran some simple code:
int main(int argc, const char * argv[])
{
Treasure x1(2);
cout << x1.get_value(0, 0) << endl;
return 0;
}
For some reason when I ran the code the terminal window just had a flashing cursor and the CPU shot up to 100% and the memory usage went up to 1.5GB in a matter of seconds.
Does anyone have any idea on why this is happening? It's been awhile since I've used C++, so I might just be missing something obvious.
You are using size in your constructor before setting its value. So you will just have a garbage value there. Just move
size = boardSize;
up a few lines
In constructor, you didn't initialize "size" in the loop
for (int i = 0; i < size; i ++)
size here is undefined, and whatever garbage is here, it will be used in a loop
Just in support of the already provided answers, your size variable has been declared but not initialised! In such a case, you're leaving it up to the compiler to assign a value to size which may or may not be 0.
Rule of thumb is to always initialise variables to a value i.e. size = boardSize, even pointers in which case set them to NULL. Setting the "size" to the your input should fix the problem :)

How to create an array of pointers inside a function whose size is not known till run time

In main I can:
Node* myNodeArray2[myHeight][myWidth];//Does not call constructor
for(int i=0; i<myHeight; i++){
for(int j=0; j<myWidth; j++){
theNodeArray[i][j] = new Node("ThisIsTest", 5, 5);
}
}
So for the above code myHeight and myWidth can be user input at run time. It does not call the default constructor and I can use the new operator and go through the array creating the objects.
I want to be able to pass Node* myNodeArray2 to a function and let it create the array size and populate it. When it is created I want the elements to be pointers. I don't want to call the default constructor. I want to be able to at my choosing call the new operator with the non-default constructor.
When I try:
void Test(Node*& theNodeArray, int myHeight, int myWidth){
theNodeArray = new Node*[myHeight][myWidth];
}
int main(){
Node* myNodeArray;
Test(myNodeArray, myHeight, myWidth);
}
I get that
"myWidth is not a constant expression."
I have tried a couple of different methods but cannot get what I want. I need the creation to happen in a separate function. I need to be able to define the size at runtime. Any help?
Edit:
I don't want to use std::vector.
Edit 2:
I don't want to do this
int** ary = new int*[sizeX];
for(int i = 0; i < sizeX; ++i)
ary[i] = new int[sizeY];
As this forces the rows to be of objects of contiguous memory space. I want to allocate a 2d array of pointers. I do not want to necessarily create the objects that will be pointed to.
You may use the following:
Node*** MakeArrayNodePtr(int myHeight, int myWidth){
Node*** res = new Node**[myHeight];
for (int i = 0; i != myHeight; ++i) {
res[i] = new Node*[myWidth]();
}
return res;
}
And don't forget
void DeleteArrayNodePtr(Node*** nodes, int myHeight, int myWidth)
{
for (int i = 0; i != myHeight; ++i) {
// And probably:
/*
for (int j = 0; j != myWidth; ++j) {
delete nodes[i][j];
}
*/
delete [] nodes[i];
}
delete [] nodes;
}

Initialized in a function and is not initialized in main

I am trying to allocate memory in a function and I am not sure what I am doing wrong.
I want this:
int main()
{
int* test= 0;
initialize(test, 10);
int test2 = test[2];
delete[] test;
}
void initialize(int* test, int count)
{
test = new int[count];
for (int i = 0; i < count; i++)
{
test[i] = i;
}
}
But I receive this error: Unhandled exception at 0x770d15de in Robust Simulation.exe: 0xC0000005: Access violation reading location 0x00000008.
It breaks on line: int test2 = test[2];
but this works:
int main()
{
int* test=0;
test = new int[10];
for (int i = 0; i < 10; i++)
{
test[i] = i;
}
int test2 = test[2];
delete[] test;
}
Is there a scoping problem? I thought since I pass it a pointer it would be allocated and I would be able to access it outside of the initialize function.
Thanks for your help
Do following changes:-
initialize(&test, 10);
....
void initialize(int** test, int count)
{
*test = new int[count];
for (int i = 0; i < count; i++)
{ (*test)[i] = i; }
}
C++ has another feature called references if you want as it is :-
void initialize(int*& test, int count)
{
test = new int[count];
for (int i = 0; i < count; i++)
{ test[i] = i; }
}
what you are doing is passing the test[from main](address will pass) and storing in another local pointer variable named test.This new variable has lifetime of function scope and will get soon deleted leaving garbage after the completion of function.
Another option is
int* test= initialize(test, 10);
and change initialize as
int* initialize(int* test, int count)
{
test = new int[count];
for (int i = 0; i < count; i++)
{ test[i] = i; }
return test;
}
Pointers are also passed by value. You need:
void initialize(int*& test, int count)
Your version doesn't change the original pointer:
void initialize(int* test, int count)
{
//test is a copy of the pointer because it was passed by value
//...
}
After this, it's obvious why the delete[] fails - because the original pointer in main is never initialized.
You need to pass a reference to a pointer into your initialise function. Change the prototype to
void initialize(int* &test, int count)
The return value of new is assigned to that copy of the pointer that gets created when passing by value. So when the function exits, that address is lost as the copy goes out of scope and so you have a memory leak. Thus your test pointer never actually points to any allocated memory and so deleting it gives you an access violation.
Passing by reference allows the test pointer to be modified by the function

Allocating 2d array of chars

Constructor
This is how I'm allocating it:
char **board = new char*[width];
for(i = 0; i < width; i++){
board[i] = new char[height];
for(j = 0; j < height; j++)
board[i][j] = 0;
}
this->board = &board;
Inside the class, it's:
char ***board;
Destructor:
Now I want to delete it, so I wrote this (the board it the class field):
for(i = 0; i < width; i++)
delete (*board)[i];
delete (*board);
When running this:
Board* b = new Board(16, 30, 99);
delete b;
I get an Unhandled exception. Why?
You are storing a pointer to a variable on the stack, which becomes invalid as soon as the constructor returns. You should declare your class's data member as char **board and assign this->board = board.
EDIT: See also #Kerrek SB's comment. The local variable is redundant. Just use the data member directly (without the this->).
EDIT 2: Rectangular arrays are best created as a single array, using pointer arithmetic to index (which is what the compiler does with declared 2D arrays anyway):
char *board;
...
board = new char[width*height];
for(i = 0; i < width*height; ++i){
board[i] = 0;
}
...
char& operator()(int i, int j) { return board[width*i + j]; }
This has the advantage of requiring just one memory allocation (and therefore one delete[]). It also improves cache locality because the cells are contiguous.
Even better, if you know the dimensions at compile-time, use templates:
template <int W, int H>
class Board {
char board[W][H];
...
};
...
Board<8, 8>* b = new Board<8, 8>(...);
This requires no memory allocation at all (other than the new Board, of course).
Anything that you new you need to delete, in the exact same way:
board = new char*[width];
...
board[i] = new char[height];
...
...
delete[] board[i];
delete[] board;
No dereferencing is needed in this case.
You should use the powers of C++.
class Board
{
std::vector<std::vector<char>> board;
public:
Board(std::vector<std::vector<char>> const& board) : board(board) {}
Board(size_t x, size_t y, char val = 0)
{
std::vector<char> x2(x, val);
this->board(y, x2);
}
};
All you've got to do now is board[y].push_back(char_x_val) in order to append a new element to the end. You can treat board[y][x] just like any other 2D array (well, almost), but not worry about the deallocation.
Read up more on vectors here. (Anyone know a good tutorial?)