I am working on an assignment that requires me to simulate Langton's ant. I have dynamically allocated memory for a 2D array in the constructor of class Ant. The pointer to this array is a member of class Ant. Additionally, I have defined get functions for the rows and columns which I am using to pass these values to my array.
Ant.hpp
#ifndef ANT_HPP
#define ANT_HPP
enum Direction {UP, RIGHT, DOWN, LEFT};
class Ant
{
private:
char** board;
char spaceColor;
Direction facing;
int rows, cols, steps, stepNumber;
int startRow, startCol, tempCol, tempRow;
int lastRow, lastCol;
int thisRow, thisCol;
public:
Ant();
Ant(int, int, int, int, int);
void print();
void makeMove();
};
Ant.cpp
Ant::Ant()
{
rows = 5;
cols = 5;
steps = 5;
startRow = 0;
startCol = 0;
stepNumber = 0;
facing = LEFT;
setThisRow(5);
setThisCol(5);
setLastRow(5);
setLastCol(5);
setSpaceColor(' ');
board = new char*[rows];
for(int i = 0; i < rows; ++i){
board[i] = new char[cols];
}
for(int i = 0; i < rows; ++i){
for(int i = 0; i < rows; ++i){
board[i][j] = ' ';
}
}
board[startRow][startCol] = '*';
}
char Ant::getSpaceColor()
{
return spaceColor;
}
void Ant::makeMove()
{
if(getSpaceColor() == ' '){
board[getLastRow()][getLastCol()] = '#';
}
}
int Ant::getLastRow()
{
return lastRow;
}
int Ant::getLastCol()
{
return lastCol;
}
main.cpp
#include "Ant.hpp"
#include <iostream>
using std::cout;
using std::endl;
int main()
{
Ant myAnt;
myAnt.print();
myAnt.makeMove();
return 0;
}
Gdb has reported a segmentation fault at this line of code:
board[getLastRow()][getLastCol()] = '#';
Gdb is able to print accurate values for getLastRow() & getLastCol(), but cannot access memory for board[getLastRow()][getLastCol()].
I am not sure what I am doing wrong, any help would be greatly appreciated
Assuming board[getLastRow()][getLastCol()] translates to board[5][5], you go beyond the buffer. Your board is 0..4.
You are invoking undefined behavior by accessing array elements out of bounds. Your setLastRow(5); and
setLastCol(5); functions cause both of your getLastRow() and getLastCol() functions to return the value of 5 but since arrays are zero indexed that would imply you are accessing 6th element. So with:
board[getLastRow()][getLastCol()] = '#';
you are effectively calling:
board[5][5] = '#'; // undefined behavior because there are no 6 X 6 elements
whereas you can only have a maximum index of 4:
board[4][4] = '#'; // OK as there are 5 X 5 elements
One solution is to have your functions return lastRow - 1 and lastCol - 1 respectively.
Segmentation fault usually refers that the program is accessing an unallocated address.
board[getLastRow()][getLastCol()]
You might want to check the starting index and ending index of the arrays.
I think you might allocating the 2D array with index starting from 0
getLastRow()/Col might return the size of the row / Col
So when the index starts from 0, your last row index would be getLastRow()-1 and the same thing would apply for the Column
which yields ==> board[getLastRow()-1][getLastCol()-1]
Related
So I have a program, which helps me finding a cycles in graph by adjacency matrix. I have done everything, except output.
Realization
So, upon clicking exectute button, from masked edit control, an number up to 99 taken to for making a size of some arrays. Then I am creating 2d array **arr to fill it with zeros, and after that via for I fill info from text written in normal edit control. After this step I fill vector with edges from that array and doing DFS for that graph.
Now about problem
Like I said, I have 2d array. The whole procedure of filling it with zeros:
int **arr;
arr = new int* [x];
for (int i = 0; i < x; i++)
{
arr[i] = new int[x];
}
for (int i = 0; i < x; i++)
{
for (int j = 0; j < x; j++)
{
arr[i][j] = 0;
}
}
And with the next procedure (taking adjacency matrix from edit control) lies the warning #1:
int i = 0, j;
int lpos = 0;
for (CString line = s.Tokenize(_T("\r\n"), lpos); lpos > 0; line = s.Tokenize(_T("\r\n"), lpos))
{
j = 0;
int cpos = 0;
for (CString cell = line.Tokenize(_T(" "), cpos); cpos > 0; cell = line.Tokenize(_T(" "), cpos))
{
int num;
num = _wtoi(cell);
arr[i][j] = num;
j++;
}
i++;
}
Warning C6386 Buffer overrun while writing to 'arr[i]': the writable size is 'x*4' bytes, but '8' bytes might be written.
And before making output, I also put in another vector cycles and it also has warning #2:
for (int i = 1; i <= edges; i++) {
if (mark[i] != 0) {
int k = mark[i];
cycles[k].push_back(i);
}
}
Warning C6385 Reading invalid data from 'mark': the readable size is 'x*4' bytes, but '8' bytes may be read.
The problem is, when I tested output (adjacency matrix 7x7, all filled with 1), it catches an exception for those 2 pieces, which is being warnings. The exceptions is: Exception thrown at 0x00007FF6DD63AD7A in CTabControl.exe: 0xC0000005: Access violation writing location 0x00000000FDFDFDFD.
What I tried
For now, I tried to use make_unique pointer as an alterative for * pointer on mark, which was declared previously like this: int *mark = new int[x]; (changed to auto mark = make_unique<int[]>(x);). After change, there is a new error appear:
E0413 no suitable conversion function from "std::unique_ptr<int [], std::default_delete<int []>>" to "int *" exists
It points out to the function, where I use mark array: dfs_cycle(1, 0, color, mark, par, cyclenumber);
The function declared like this:
void dfs_cycle(int u, int p, int color[], int mark[], int par[], int& cyclenumber)
{
// ........
}
What can I do here to fix that?
EDIT
I think I found the problem, yet for now I can't find a solution. So, when the text is being read from text box, where adjacency matrix is, I am filling up the array with the contents of tokenized text. Here's how I am doing it:
int i = 0, j; int lpos = 0;
for (CString line = s.Tokenize(_T("\r\n"), lpos); lpos > 0; line = s.Tokenize(_T("\r\n"), lpos)){
j = 0;
int cpos = 0;
for (CString cell = line.Tokenize(_T(" "), cpos); cpos > 0; cell = line.Tokenize(_T(" "), cpos))
{
int num;
num = _wtoi(cell);
arr[i][j] = num;
j++;
}
i++;
}
When I try to make arr a 2d vector, I stumbled upon "out of range" error. So, that means I have to somehow tokenize my text and put it in array. I haven't figured out how.
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.
I've been working on a class for an insertion sort thing that I'm playing around with. However, when I run my program, it seems to work just fine for the most part (gets to return 0; in main and then freezes). I don't know why or how it's freezing, and it's gotten me quite confused.
The only method that is called from the insertionSort object is sort, if you don't count generateNums.
Main.cpp:
#include "stdafx.h"
#include "insertionSort.h"
#include <iostream>
int main()
{
int* gotNums;
const int INT_LENGTH = 100;
//Create new insertionSort object
insertionSort insSort(INT_LENGTH); //Length: 100
std::cout << "hey";
return 0;
}
insertionSort.h:
#pragma once
class insertionSort
{
private:
int* _nums; //Sorted and unsorted nums
int _sortedBegins; //Point at which sorted items begin. This minus one is the first unsorted item
int _length;
void shiftUnsorted();
public:
insertionSort(int length);
int* getNums();
void sortNums();
void generateNums();
};
insertionSort.cpp
#include "stdafx.h"
#include "insertionSort.h"
#include <random>
#include <iostream>
//Constructor and destructors
insertionSort::insertionSort(int length)
{
_nums = new int(length + 1); //+1 to accomodate empty space between sorted & unsorted.
std::cout << "made arr ";
_sortedBegins = length + 1;
std::cout << "made sorted ";
_length = length + 1;
std::cout << "made len ";
this->generateNums();
}
/* Custom functions */
//Populate array with new numbers
void insertionSort::generateNums() {
for (int i = 0; i < _length - 1; i++) { //Don't fill the last array; it's an empty place for the sorted items.
_nums[i] = rand() % 100 + 1; //generate number between 1 and 100
}
_nums[_length] = -1; //Create buffer
}
//The main part of it all - sort the array
void insertionSort::sortNums() {
int currPos = _sortedBegins - 1; //Loop backwards through the unsorted items so that there is minimal shifting.
int currInt;
while (currPos > 0) {
currInt = _nums[currPos];
for (int i = _length; i > _sortedBegins; i++) {
if (i < currInt) { //Time to shift the sorted to the left
_nums[_sortedBegins - 1] = 0; //Shift buffer left
for (int i2 = _sortedBegins + 1; i2 <= i; i2++) { //Shift main sorted content left
_nums[i2] = _nums[i2 + 1];
}
_nums[i] = currInt;
break;
}
}
currInt--;
}
}
//Get nums from array
int* insertionSort::getNums() {
return _nums;
}
//Shift unsorted items to the left to make way for new data in sorted. NOTE: does not assign new value to sortedBegins.
void insertionSort::shiftUnsorted() {
for (int i = 0; i < _sortedBegins - 1; i++) {
_nums[i] = _nums[i + 1];
}
_nums[_sortedBegins - 1] = 0;
//And, it's hopefully shifted!
}
Anyone got an idea as to why this isn't working properly?
Thanks,
- Sam
Change:
_nums[_length] = -1; //Create buffer
to:
_nums[_length - 1] = -1; //Create buffer
Valid indexes for _nums are from 0 to length-1. Your code is writing outside the array, which causes undefined behavior.
The for loop in sortNums is also doesn't look right:
for (i = _length; i > _sortedBegins; i++) {
It makes no sense to start at _length, which is after the end of the array. And adding to it goes even farther out of the array. I haven't really analyzed the logic in that loop, so I'm not sure what the correct code is. But you need to start by making sure you stay inside the array.
But since your program doesn't currently call sortNums, it won't cause a problem now.
When shiftUnsorted does
_nums[_sortedBegins - 1] = 0;
you'll write outside the array if _sortedBegins is 0. You don't currently call this, either. When you add the call to it, make sure it can never be called when that's true, or add a check for this into the function.
This code looks suspicious to me:
_nums = new int(length + 1);
I would have expected square brackets instead of round parentheses. Because like this, you are only creating a pointer to a single int that is initialized with the value 101. But instead you wanted to create an array of 101 ints and later fill it with values. So write this:
_nums = new int[length + 1];
I'm trying to create a magic square that will print four different grid sizes (5x5, 7x7, 9x9, 15x15). The error I'm having is the array magsquare within the function tells me it needs a constant integer. (I can't use pointers) This is a class assignment.
#include <iostream>
#include <iomanip>
using namespace std;
void magicSquare(int n){
int magsquare[n][n] = { 0 }; /*THIS is the error with [n][n]*/
int gridsize = n * n;
int row = 0;
int col = n / 2;
for (int i = 1; i <= gridsize; ++i)
{
magsquare[row][col] = i;
row--;
col++;
if (i%n == 0)
{
row += 2;
--col;
}
else
{
if (col == n)
col -= n;
else if (row < 0)
row += n;
}
}
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++){
cout << setw(3) << right << magsquare[i][j];
}
cout << endl;
}
}
int main(){
int n = 5;
magicSquare(n);
return 0;
}
Indentation may look incorrect, but it's right. Sorry.
The failure is because standard C++ cannot allocate dynamically sized array on the stack, as you are trying to do.
int magsquare[n][n];
As far as magicSquare is concerned n is only known at runtime and for an array to be allocated on the stack it's size must be known at compile time.
Use a 15 x 15 array.
int magsquare[15][15];
As long as you know this is the largest you'll ever need, you should be ok.
Alternatives (which you've already said you can't use)
Use new to declare a 2d array of the required dimensions. (Remember to delete[] it though)
Use std::vector
It may also be a good idea to add a check that n values over 15 or under 1 are rejected, otherwise you'll face undefined behaviour if any values outside of 1-15 are passed into the function.
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 :)